summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--COPYRIGHT.txt8
-rw-r--r--modules/bullet/area_bullet.cpp150
-rw-r--r--modules/bullet/area_bullet.h51
-rw-r--r--modules/bullet/collision_object_bullet.cpp10
-rw-r--r--modules/bullet/space_bullet.cpp148
-rw-r--r--modules/tinyexr/SCsub3
-rw-r--r--modules/tinyexr/image_loader_tinyexr.cpp2
-rw-r--r--modules/tinyexr/image_saver_tinyexr.cpp2
-rw-r--r--modules/webp/SCsub1
-rw-r--r--modules/websocket/SCsub3
-rw-r--r--servers/physics_2d/godot_area_2d.cpp1
-rw-r--r--servers/physics_2d/godot_area_pair_2d.cpp10
-rw-r--r--servers/physics_2d/godot_area_pair_2d.h2
-rw-r--r--servers/physics_3d/godot_area_3d.cpp1
-rw-r--r--servers/physics_3d/godot_area_pair_3d.cpp10
-rw-r--r--servers/physics_3d/godot_area_pair_3d.h2
-rw-r--r--thirdparty/README.md57
-rw-r--r--thirdparty/certs/ca-certificates.crt159
-rw-r--r--thirdparty/graphite/ChangeLog238
-rw-r--r--thirdparty/graphite/src/Pass.cpp9
-rw-r--r--thirdparty/libogg/framing.c9
-rw-r--r--thirdparty/libogg/ogg/config_types.h15
-rw-r--r--thirdparty/libvorbis/COPYING2
-rw-r--r--thirdparty/libvorbis/analysis.c2
-rw-r--r--thirdparty/libvorbis/backends.h2
-rw-r--r--thirdparty/libvorbis/barkmel.c2
-rw-r--r--thirdparty/libvorbis/bitrate.c2
-rw-r--r--thirdparty/libvorbis/bitrate.h2
-rw-r--r--thirdparty/libvorbis/block.c2
-rw-r--r--thirdparty/libvorbis/books/coupled/res_books_51.h2
-rw-r--r--thirdparty/libvorbis/books/coupled/res_books_stereo.h2
-rw-r--r--thirdparty/libvorbis/books/floor/floor_books.h2
-rw-r--r--thirdparty/libvorbis/books/uncoupled/res_books_uncoupled.h2
-rw-r--r--thirdparty/libvorbis/codebook.c2
-rw-r--r--thirdparty/libvorbis/codebook.h2
-rw-r--r--thirdparty/libvorbis/codec_internal.h2
-rw-r--r--thirdparty/libvorbis/envelope.c2
-rw-r--r--thirdparty/libvorbis/envelope.h2
-rw-r--r--thirdparty/libvorbis/floor0.c2
-rw-r--r--thirdparty/libvorbis/floor1.c2
-rw-r--r--thirdparty/libvorbis/highlevel.h2
-rw-r--r--thirdparty/libvorbis/info.c22
-rw-r--r--thirdparty/libvorbis/lookup.c2
-rw-r--r--thirdparty/libvorbis/lookup.h2
-rw-r--r--thirdparty/libvorbis/lookup_data.h2
-rw-r--r--thirdparty/libvorbis/lpc.c2
-rw-r--r--thirdparty/libvorbis/lpc.h2
-rw-r--r--thirdparty/libvorbis/lsp.c5
-rw-r--r--thirdparty/libvorbis/lsp.h2
-rw-r--r--thirdparty/libvorbis/mapping0.c2
-rw-r--r--thirdparty/libvorbis/masking.h2
-rw-r--r--thirdparty/libvorbis/mdct.c2
-rw-r--r--thirdparty/libvorbis/mdct.h2
-rw-r--r--thirdparty/libvorbis/misc.h2
-rw-r--r--thirdparty/libvorbis/modes/floor_all.h2
-rw-r--r--thirdparty/libvorbis/modes/psych_11.h2
-rw-r--r--thirdparty/libvorbis/modes/psych_16.h2
-rw-r--r--thirdparty/libvorbis/modes/psych_44.h2
-rw-r--r--thirdparty/libvorbis/modes/psych_8.h2
-rw-r--r--thirdparty/libvorbis/modes/residue_16.h2
-rw-r--r--thirdparty/libvorbis/modes/residue_44.h2
-rw-r--r--thirdparty/libvorbis/modes/residue_44p51.h2
-rw-r--r--thirdparty/libvorbis/modes/residue_44u.h2
-rw-r--r--thirdparty/libvorbis/modes/residue_8.h2
-rw-r--r--thirdparty/libvorbis/modes/setup_11.h2
-rw-r--r--thirdparty/libvorbis/modes/setup_16.h2
-rw-r--r--thirdparty/libvorbis/modes/setup_22.h2
-rw-r--r--thirdparty/libvorbis/modes/setup_32.h2
-rw-r--r--thirdparty/libvorbis/modes/setup_44.h2
-rw-r--r--thirdparty/libvorbis/modes/setup_44p51.h2
-rw-r--r--thirdparty/libvorbis/modes/setup_44u.h2
-rw-r--r--thirdparty/libvorbis/modes/setup_8.h2
-rw-r--r--thirdparty/libvorbis/modes/setup_X.h2
-rw-r--r--thirdparty/libvorbis/os.h13
-rw-r--r--thirdparty/libvorbis/psy.c26
-rw-r--r--thirdparty/libvorbis/psy.h2
-rw-r--r--thirdparty/libvorbis/psytune.c2
-rw-r--r--thirdparty/libvorbis/registry.c2
-rw-r--r--thirdparty/libvorbis/registry.h2
-rw-r--r--thirdparty/libvorbis/res0.c5
-rw-r--r--thirdparty/libvorbis/scales.h2
-rw-r--r--thirdparty/libvorbis/sharedbook.c17
-rw-r--r--thirdparty/libvorbis/smallft.c2
-rw-r--r--thirdparty/libvorbis/smallft.h2
-rw-r--r--thirdparty/libvorbis/synthesis.c2
-rw-r--r--thirdparty/libvorbis/vorbis/codec.h2
-rw-r--r--thirdparty/libvorbis/vorbis/vorbisenc.h2
-rw-r--r--thirdparty/libvorbis/vorbis/vorbisfile.h2
-rw-r--r--thirdparty/libvorbis/vorbisenc.c5
-rw-r--r--thirdparty/libvorbis/vorbisfile.c25
-rw-r--r--thirdparty/libvorbis/window.c2
-rw-r--r--thirdparty/libvorbis/window.h2
-rw-r--r--thirdparty/libwebp/AUTHORS9
-rw-r--r--thirdparty/libwebp/src/dec/alpha_dec.c2
-rw-r--r--thirdparty/libwebp/src/dec/buffer_dec.c10
-rw-r--r--thirdparty/libwebp/src/dec/frame_dec.c2
-rw-r--r--thirdparty/libwebp/src/dec/io_dec.c151
-rw-r--r--thirdparty/libwebp/src/dec/vp8_dec.c14
-rw-r--r--thirdparty/libwebp/src/dec/vp8i_dec.h4
-rw-r--r--thirdparty/libwebp/src/dec/vp8l_dec.c23
-rw-r--r--thirdparty/libwebp/src/dec/webp_dec.c17
-rw-r--r--thirdparty/libwebp/src/dec/webpi_dec.h4
-rw-r--r--thirdparty/libwebp/src/demux/anim_decode.c23
-rw-r--r--thirdparty/libwebp/src/demux/demux.c25
-rw-r--r--thirdparty/libwebp/src/dsp/alpha_processing.c73
-rw-r--r--thirdparty/libwebp/src/dsp/alpha_processing_neon.c21
-rw-r--r--thirdparty/libwebp/src/dsp/alpha_processing_sse2.c42
-rw-r--r--thirdparty/libwebp/src/dsp/alpha_processing_sse41.c6
-rw-r--r--thirdparty/libwebp/src/dsp/cost.c4
-rw-r--r--thirdparty/libwebp/src/dsp/cpu.c45
-rw-r--r--thirdparty/libwebp/src/dsp/dec.c6
-rw-r--r--thirdparty/libwebp/src/dsp/dec_neon.c68
-rw-r--r--thirdparty/libwebp/src/dsp/dsp.h106
-rw-r--r--thirdparty/libwebp/src/dsp/enc.c6
-rw-r--r--thirdparty/libwebp/src/dsp/filters.c4
-rw-r--r--thirdparty/libwebp/src/dsp/filters_sse2.c5
-rw-r--r--thirdparty/libwebp/src/dsp/lossless.c66
-rw-r--r--thirdparty/libwebp/src/dsp/lossless.h17
-rw-r--r--thirdparty/libwebp/src/dsp/lossless_common.h13
-rw-r--r--thirdparty/libwebp/src/dsp/lossless_enc.c198
-rw-r--r--thirdparty/libwebp/src/dsp/lossless_enc_sse2.c133
-rw-r--r--thirdparty/libwebp/src/dsp/lossless_enc_sse41.c121
-rw-r--r--thirdparty/libwebp/src/dsp/lossless_sse2.c1
-rw-r--r--thirdparty/libwebp/src/dsp/lossless_sse41.c132
-rw-r--r--thirdparty/libwebp/src/dsp/rescaler.c11
-rw-r--r--thirdparty/libwebp/src/dsp/ssim.c2
-rw-r--r--thirdparty/libwebp/src/dsp/upsampling.c10
-rw-r--r--thirdparty/libwebp/src/dsp/yuv.c20
-rw-r--r--thirdparty/libwebp/src/enc/alpha_enc.c8
-rw-r--r--thirdparty/libwebp/src/enc/analysis_enc.c60
-rw-r--r--thirdparty/libwebp/src/enc/backward_references_enc.c201
-rw-r--r--thirdparty/libwebp/src/enc/backward_references_enc.h20
-rw-r--r--thirdparty/libwebp/src/enc/config_enc.c5
-rw-r--r--thirdparty/libwebp/src/enc/frame_enc.c20
-rw-r--r--thirdparty/libwebp/src/enc/histogram_enc.c11
-rw-r--r--thirdparty/libwebp/src/enc/histogram_enc.h6
-rw-r--r--thirdparty/libwebp/src/enc/picture_csp_enc.c14
-rw-r--r--thirdparty/libwebp/src/enc/picture_rescale_enc.c61
-rw-r--r--thirdparty/libwebp/src/enc/picture_tools_enc.c31
-rw-r--r--thirdparty/libwebp/src/enc/syntax_enc.c2
-rw-r--r--thirdparty/libwebp/src/enc/vp8i_enc.h13
-rw-r--r--thirdparty/libwebp/src/enc/vp8l_enc.c669
-rw-r--r--thirdparty/libwebp/src/enc/vp8li_enc.h4
-rw-r--r--thirdparty/libwebp/src/enc/webp_enc.c2
-rw-r--r--thirdparty/libwebp/src/mux/anim_encode.c16
-rw-r--r--thirdparty/libwebp/src/mux/muxedit.c2
-rw-r--r--thirdparty/libwebp/src/mux/muxi.h4
-rw-r--r--thirdparty/libwebp/src/mux/muxread.c6
-rw-r--r--thirdparty/libwebp/src/utils/bit_reader_inl_utils.h9
-rw-r--r--thirdparty/libwebp/src/utils/bit_reader_utils.c7
-rw-r--r--thirdparty/libwebp/src/utils/bit_reader_utils.h10
-rw-r--r--thirdparty/libwebp/src/utils/bit_writer_utils.c4
-rw-r--r--thirdparty/libwebp/src/utils/color_cache_utils.c22
-rw-r--r--thirdparty/libwebp/src/utils/huffman_encode_utils.c3
-rw-r--r--thirdparty/libwebp/src/utils/huffman_encode_utils.h2
-rw-r--r--thirdparty/libwebp/src/utils/rescaler_utils.c114
-rw-r--r--thirdparty/libwebp/src/utils/rescaler_utils.h13
-rw-r--r--thirdparty/libwebp/src/utils/utils.c11
-rw-r--r--thirdparty/libwebp/src/utils/utils.h28
-rw-r--r--thirdparty/libwebp/src/webp/decode.h2
-rw-r--r--thirdparty/libwebp/src/webp/encode.h8
-rw-r--r--thirdparty/pcre2/AUTHORS8
-rw-r--r--thirdparty/pcre2/LICENCE8
-rw-r--r--thirdparty/pcre2/src/config.h107
-rw-r--r--thirdparty/pcre2/src/pcre2.h12
-rw-r--r--thirdparty/pcre2/src/pcre2_auto_possess.c13
-rw-r--r--thirdparty/pcre2/src/pcre2_compile.c86
-rw-r--r--thirdparty/pcre2/src/pcre2_dfa_match.c69
-rw-r--r--thirdparty/pcre2/src/pcre2_error.c3
-rw-r--r--thirdparty/pcre2/src/pcre2_jit_compile.c89
-rw-r--r--thirdparty/pcre2/src/pcre2_jit_simd_inc.h819
-rw-r--r--thirdparty/pcre2/src/pcre2_match.c77
-rw-r--r--thirdparty/pcre2/src/pcre2_tables.c347
-rw-r--r--thirdparty/pcre2/src/pcre2_ucd.c6060
-rw-r--r--thirdparty/pcre2/src/pcre2_ucp.h8
-rw-r--r--thirdparty/pcre2/src/sljit/sljitConfigInternal.h14
-rw-r--r--thirdparty/pcre2/src/sljit/sljitExecAllocator.c124
-rw-r--r--thirdparty/pcre2/src/sljit/sljitLir.c25
-rw-r--r--thirdparty/pcre2/src/sljit/sljitLir.h76
-rw-r--r--thirdparty/pcre2/src/sljit/sljitNativeARM_32.c23
-rw-r--r--thirdparty/pcre2/src/sljit/sljitNativeARM_64.c21
-rw-r--r--thirdparty/pcre2/src/sljit/sljitNativeARM_T2_32.c21
-rw-r--r--thirdparty/pcre2/src/sljit/sljitNativeMIPS_32.c2
-rw-r--r--thirdparty/pcre2/src/sljit/sljitNativeMIPS_64.c2
-rw-r--r--thirdparty/pcre2/src/sljit/sljitNativeMIPS_common.c16
-rw-r--r--thirdparty/pcre2/src/sljit/sljitNativePPC_32.c26
-rw-r--r--thirdparty/pcre2/src/sljit/sljitNativePPC_64.c32
-rw-r--r--thirdparty/pcre2/src/sljit/sljitNativePPC_common.c93
-rw-r--r--thirdparty/pcre2/src/sljit/sljitNativeS390X.c1780
-rw-r--r--thirdparty/pcre2/src/sljit/sljitNativeSPARC_32.c3
-rw-r--r--thirdparty/pcre2/src/sljit/sljitNativeSPARC_common.c18
-rw-r--r--thirdparty/pcre2/src/sljit/sljitNativeX86_common.c2
-rw-r--r--thirdparty/pcre2/src/sljit/sljitUtils.c10
-rw-r--r--thirdparty/pcre2/src/sljit/sljitWXExecAllocator.c8
-rw-r--r--thirdparty/tinyexr/tinyexr.cc4
-rw-r--r--thirdparty/tinyexr/tinyexr.h9052
-rw-r--r--thirdparty/wslay/config.h (renamed from thirdparty/wslay/includes/config.h)2
-rw-r--r--thirdparty/wslay/patches/msvcfix.diff (renamed from thirdparty/wslay/msvcfix.diff)7
-rw-r--r--thirdparty/wslay/wslay/wslay.h (renamed from thirdparty/wslay/includes/wslay/wslay.h)140
-rw-r--r--thirdparty/wslay/wslay/wslayver.h (renamed from thirdparty/wslay/includes/wslay/wslayver.h)0
-rw-r--r--thirdparty/wslay/wslay_event.c887
-rw-r--r--thirdparty/wslay/wslay_event.h20
-rw-r--r--thirdparty/wslay/wslay_frame.c306
-rw-r--r--thirdparty/wslay/wslay_frame.h1
-rw-r--r--thirdparty/wslay/wslay_macro.h (renamed from thirdparty/wslay/wslay_stack.h)25
-rw-r--r--thirdparty/wslay/wslay_net.c5
-rw-r--r--thirdparty/wslay/wslay_queue.c98
-rw-r--r--thirdparty/wslay/wslay_queue.h22
-rw-r--r--thirdparty/wslay/wslay_stack.c86
-rw-r--r--thirdparty/xatlas/xatlas.cpp2108
-rw-r--r--thirdparty/xatlas/xatlas.h36
-rw-r--r--thirdparty/zstd/common/bitstream.h2
-rw-r--r--thirdparty/zstd/common/compiler.h3
-rw-r--r--thirdparty/zstd/common/cpu.h2
-rw-r--r--thirdparty/zstd/common/debug.c2
-rw-r--r--thirdparty/zstd/common/debug.h2
-rw-r--r--thirdparty/zstd/common/entropy_common.c2
-rw-r--r--thirdparty/zstd/common/error_private.c2
-rw-r--r--thirdparty/zstd/common/error_private.h6
-rw-r--r--thirdparty/zstd/common/fse.h4
-rw-r--r--thirdparty/zstd/common/fse_decompress.c40
-rw-r--r--thirdparty/zstd/common/huf.h5
-rw-r--r--thirdparty/zstd/common/mem.h8
-rw-r--r--thirdparty/zstd/common/pool.c2
-rw-r--r--thirdparty/zstd/common/pool.h2
-rw-r--r--thirdparty/zstd/common/xxhash.c6
-rw-r--r--thirdparty/zstd/common/xxhash.h2
-rw-r--r--thirdparty/zstd/common/zstd_common.c2
-rw-r--r--thirdparty/zstd/common/zstd_deps.h2
-rw-r--r--thirdparty/zstd/common/zstd_internal.h30
-rw-r--r--thirdparty/zstd/common/zstd_trace.h154
-rw-r--r--thirdparty/zstd/compress/fse_compress.c2
-rw-r--r--thirdparty/zstd/compress/hist.c2
-rw-r--r--thirdparty/zstd/compress/hist.h2
-rw-r--r--thirdparty/zstd/compress/huf_compress.c79
-rw-r--r--thirdparty/zstd/compress/zstd_compress.c1863
-rw-r--r--thirdparty/zstd/compress/zstd_compress_internal.h208
-rw-r--r--thirdparty/zstd/compress/zstd_compress_literals.c8
-rw-r--r--thirdparty/zstd/compress/zstd_compress_literals.h2
-rw-r--r--thirdparty/zstd/compress/zstd_compress_sequences.c20
-rw-r--r--thirdparty/zstd/compress/zstd_compress_sequences.h2
-rw-r--r--thirdparty/zstd/compress/zstd_compress_superblock.c289
-rw-r--r--thirdparty/zstd/compress/zstd_compress_superblock.h2
-rw-r--r--thirdparty/zstd/compress/zstd_cwksp.h195
-rw-r--r--thirdparty/zstd/compress/zstd_double_fast.c6
-rw-r--r--thirdparty/zstd/compress/zstd_double_fast.h2
-rw-r--r--thirdparty/zstd/compress/zstd_fast.c10
-rw-r--r--thirdparty/zstd/compress/zstd_fast.h2
-rw-r--r--thirdparty/zstd/compress/zstd_lazy.c1056
-rw-r--r--thirdparty/zstd/compress/zstd_lazy.h40
-rw-r--r--thirdparty/zstd/compress/zstd_ldm.c462
-rw-r--r--thirdparty/zstd/compress/zstd_ldm.h5
-rw-r--r--thirdparty/zstd/compress/zstd_ldm_geartab.h103
-rw-r--r--thirdparty/zstd/compress/zstd_opt.c2
-rw-r--r--thirdparty/zstd/compress/zstd_opt.h2
-rw-r--r--thirdparty/zstd/compress/zstdmt_compress.c32
-rw-r--r--thirdparty/zstd/compress/zstdmt_compress.h10
-rw-r--r--thirdparty/zstd/decompress/huf_decompress.c87
-rw-r--r--thirdparty/zstd/decompress/zstd_ddict.c2
-rw-r--r--thirdparty/zstd/decompress/zstd_ddict.h2
-rw-r--r--thirdparty/zstd/decompress/zstd_decompress.c253
-rw-r--r--thirdparty/zstd/decompress/zstd_decompress_block.c92
-rw-r--r--thirdparty/zstd/decompress/zstd_decompress_block.h2
-rw-r--r--thirdparty/zstd/decompress/zstd_decompress_internal.h19
-rw-r--r--thirdparty/zstd/zstd.h325
-rw-r--r--thirdparty/zstd/zstd_errors.h (renamed from thirdparty/zstd/common/zstd_errors.h)2
266 files changed, 15983 insertions, 16201 deletions
diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt
index 7ffe3dd685..7b212485ba 100644
--- a/COPYRIGHT.txt
+++ b/COPYRIGHT.txt
@@ -369,8 +369,8 @@ License: Apache-2.0
Files: ./thirdparty/pcre2/
Comment: PCRE2
-Copyright: 1997-2020, University of Cambridge
- 2009-2020, Zoltan Herczeg
+Copyright: 1997-2021, University of Cambridge
+ 2009-2021, Zoltan Herczeg
License: BSD-3-clause
Files: ./thirdparty/pvrtccompressor/
@@ -400,7 +400,7 @@ License: Expat
Files: ./thirdparty/tinyexr/
Comment: TinyEXR
-Copyright: 2014-2020, Syoyo Fujita
+Copyright: 2014-2021, Syoyo Fujita
2002, Industrial Light & Magic, a division of Lucas Digital Ltd. LLC
License: BSD-3-clause
@@ -447,7 +447,7 @@ License: Zlib
Files: ./thirdparty/zstd/
Comment: Zstandard
-Copyright: 2016-2020, Facebook, Inc.
+Copyright: 2016-2021, Facebook, Inc.
License: BSD-3-clause
diff --git a/modules/bullet/area_bullet.cpp b/modules/bullet/area_bullet.cpp
index 0d4982baba..1c49029570 100644
--- a/modules/bullet/area_bullet.cpp
+++ b/modules/bullet/area_bullet.cpp
@@ -59,8 +59,8 @@ AreaBullet::AreaBullet() :
AreaBullet::~AreaBullet() {
// signal are handled by godot, so just clear without notify
- for (int i = overlappingObjects.size() - 1; 0 <= i; --i) {
- overlappingObjects[i].object->on_exit_area(this);
+ for (int i = 0; i < overlapping_shapes.size(); i++) {
+ overlapping_shapes[i].other_object->on_exit_area(this);
}
}
@@ -70,20 +70,26 @@ void AreaBullet::dispatch_callbacks() {
}
isScratched = false;
- // Reverse order because I've to remove EXIT objects
- for (int i = overlappingObjects.size() - 1; 0 <= i; --i) {
- OverlappingObjectData &otherObj = overlappingObjects.write[i];
+ // Reverse order so items can be removed.
+ for (int i = overlapping_shapes.size() - 1; i >= 0; i--) {
+ OverlappingShapeData &overlapping_shape = overlapping_shapes.write[i];
- switch (otherObj.state) {
+ switch (overlapping_shape.state) {
case OVERLAP_STATE_ENTER:
- otherObj.state = OVERLAP_STATE_INSIDE;
- call_event(otherObj.object, PhysicsServer3D::AREA_BODY_ADDED);
- otherObj.object->on_enter_area(this);
+ overlapping_shape.state = OVERLAP_STATE_INSIDE;
+ call_event(overlapping_shape, PhysicsServer3D::AREA_BODY_ADDED);
+ if (_overlapping_shape_count(overlapping_shape.other_object) == 1) {
+ // This object's first shape being added.
+ overlapping_shape.other_object->on_enter_area(this);
+ }
break;
case OVERLAP_STATE_EXIT:
- call_event(otherObj.object, PhysicsServer3D::AREA_BODY_REMOVED);
- otherObj.object->on_exit_area(this);
- overlappingObjects.remove(i); // Remove after callback
+ call_event(overlapping_shape, PhysicsServer3D::AREA_BODY_REMOVED);
+ if (_overlapping_shape_count(overlapping_shape.other_object) == 1) {
+ // This object's last shape being removed.
+ overlapping_shape.other_object->on_exit_area(this);
+ }
+ overlapping_shapes.remove(i); // Remove after callback
break;
case OVERLAP_STATE_INSIDE: {
if (otherObj.object->getType() == TYPE_RIGID_BODY) {
@@ -98,8 +104,8 @@ void AreaBullet::dispatch_callbacks() {
}
}
-void AreaBullet::call_event(CollisionObjectBullet *p_otherObject, PhysicsServer3D::AreaBodyStatus p_status) {
- InOutEventCallback &event = eventsCallbacks[static_cast<int>(p_otherObject->getType())];
+void AreaBullet::call_event(const OverlappingShapeData &p_overlapping_shape, PhysicsServer3D::AreaBodyStatus p_status) {
+ InOutEventCallback &event = eventsCallbacks[static_cast<int>(p_overlapping_shape.other_object->getType())];
if (!event.event_callback.is_valid()) {
event.event_callback = Callable();
@@ -107,54 +113,92 @@ void AreaBullet::call_event(CollisionObjectBullet *p_otherObject, PhysicsServer3
}
call_event_res[0] = p_status;
- call_event_res[1] = p_otherObject->get_self(); // Other body
- call_event_res[2] = p_otherObject->get_instance_id(); // instance ID
- call_event_res[3] = 0; // other_body_shape ID
- call_event_res[4] = 0; // self_shape ID
+ call_event_res[1] = p_overlapping_shape.other_object->get_self(); // RID
+ call_event_res[2] = p_overlapping_shape.other_object->get_instance_id(); // Object ID
+ call_event_res[3] = p_overlapping_shape.other_shape_id; // Other object's shape ID
+ call_event_res[4] = p_overlapping_shape.our_shape_id; // This area's shape ID
Callable::CallError outResp;
Variant ret;
event.event_callback.call((const Variant **)call_event_res, 5, ret, outResp);
}
-void AreaBullet::scratch() {
- if (isScratched) {
- return;
+int AreaBullet::_overlapping_shape_count(CollisionObjectBullet *p_other_object) {
+ int count = 0;
+ for (int i = 0; i < overlapping_shapes.size(); i++) {
+ if (overlapping_shapes[i].other_object == p_other_object) {
+ count++;
+ }
}
- isScratched = true;
+ return count;
}
-void AreaBullet::clear_overlaps(bool p_notify) {
- for (int i = overlappingObjects.size() - 1; 0 <= i; --i) {
- if (p_notify) {
- call_event(overlappingObjects[i].object, PhysicsServer3D::AREA_BODY_REMOVED);
+int AreaBullet::_find_overlapping_shape(CollisionObjectBullet *p_other_object, uint32_t p_other_shape_id, uint32_t p_our_shape_id) {
+ for (int i = 0; i < overlapping_shapes.size(); i++) {
+ const OverlappingShapeData &overlapping_shape = overlapping_shapes[i];
+ if (overlapping_shape.other_object == p_other_object && overlapping_shape.other_shape_id == p_other_shape_id && overlapping_shape.our_shape_id == p_our_shape_id) {
+ return i;
}
- overlappingObjects[i].object->on_exit_area(this);
}
- overlappingObjects.clear();
+ return -1;
}
-void AreaBullet::remove_overlap(CollisionObjectBullet *p_object, bool p_notify) {
- for (int i = overlappingObjects.size() - 1; 0 <= i; --i) {
- if (overlappingObjects[i].object == p_object) {
- if (p_notify) {
- call_event(overlappingObjects[i].object, PhysicsServer3D::AREA_BODY_REMOVED);
- }
- overlappingObjects[i].object->on_exit_area(this);
- overlappingObjects.remove(i);
- break;
+void AreaBullet::mark_all_overlaps_dirty() {
+ OverlappingShapeData *overlapping_shapes_w = overlapping_shapes.ptrw();
+ for (int i = 0; i < overlapping_shapes.size(); i++) {
+ // Don't overwrite OVERLAP_STATE_ENTER state.
+ if (overlapping_shapes_w[i].state != OVERLAP_STATE_ENTER) {
+ overlapping_shapes_w[i].state = OVERLAP_STATE_DIRTY;
}
}
}
-int AreaBullet::find_overlapping_object(CollisionObjectBullet *p_colObj) {
- const int size = overlappingObjects.size();
- for (int i = 0; i < size; ++i) {
- if (overlappingObjects[i].object == p_colObj) {
- return i;
+void AreaBullet::mark_object_overlaps_inside(CollisionObjectBullet *p_other_object) {
+ OverlappingShapeData *overlapping_shapes_w = overlapping_shapes.ptrw();
+ for (int i = 0; i < overlapping_shapes.size(); i++) {
+ if (overlapping_shapes_w[i].other_object == p_other_object && overlapping_shapes_w[i].state == OVERLAP_STATE_DIRTY) {
+ overlapping_shapes_w[i].state = OVERLAP_STATE_INSIDE;
+ }
+ }
+}
+
+void AreaBullet::set_overlap(CollisionObjectBullet *p_other_object, uint32_t p_other_shape_id, uint32_t p_our_shape_id) {
+ int i = _find_overlapping_shape(p_other_object, p_other_shape_id, p_our_shape_id);
+ if (i == -1) { // Not found, create new one.
+ OverlappingShapeData overlapping_shape(p_other_object, OVERLAP_STATE_ENTER, p_other_shape_id, p_our_shape_id);
+ overlapping_shapes.push_back(overlapping_shape);
+ p_other_object->notify_new_overlap(this);
+ isScratched = true;
+ } else {
+ overlapping_shapes.ptrw()[i].state = OVERLAP_STATE_INSIDE;
+ }
+}
+
+void AreaBullet::mark_all_dirty_overlaps_as_exit() {
+ OverlappingShapeData *overlapping_shapes_w = overlapping_shapes.ptrw();
+ for (int i = 0; i < overlapping_shapes.size(); i++) {
+ if (overlapping_shapes[i].state == OVERLAP_STATE_DIRTY) {
+ overlapping_shapes_w[i].state = OVERLAP_STATE_EXIT;
+ isScratched = true;
+ }
+ }
+}
+
+void AreaBullet::remove_object_overlaps(CollisionObjectBullet *p_object) {
+ // Reverse order so items can be removed.
+ for (int i = overlapping_shapes.size() - 1; i >= 0; i--) {
+ if (overlapping_shapes[i].other_object == p_object) {
+ overlapping_shapes.remove(i);
}
}
- return -1;
+}
+
+void AreaBullet::clear_overlaps() {
+ for (int i = 0; i < overlapping_shapes.size(); i++) {
+ call_event(overlapping_shapes[i], PhysicsServer3D::AREA_BODY_REMOVED);
+ overlapping_shapes[i].other_object->on_exit_area(this);
+ }
+ overlapping_shapes.clear();
}
void AreaBullet::set_monitorable(bool p_monitorable) {
@@ -182,7 +226,7 @@ void AreaBullet::reload_body() {
void AreaBullet::set_space(SpaceBullet *p_space) {
// Clear the old space if there is one
if (space) {
- clear_overlaps(false);
+ clear_overlaps();
isScratched = false;
// Remove this object form the physics world
@@ -203,24 +247,6 @@ void AreaBullet::on_collision_filters_change() {
updated = true;
}
-void AreaBullet::add_overlap(CollisionObjectBullet *p_otherObject) {
- scratch();
- overlappingObjects.push_back(OverlappingObjectData(p_otherObject, OVERLAP_STATE_ENTER));
- p_otherObject->notify_new_overlap(this);
-}
-
-void AreaBullet::put_overlap_as_exit(int p_index) {
- scratch();
- overlappingObjects.write[p_index].state = OVERLAP_STATE_EXIT;
-}
-
-void AreaBullet::put_overlap_as_inside(int p_index) {
- // This check is required to be sure this body was inside
- if (OVERLAP_STATE_DIRTY == overlappingObjects[p_index].state) {
- overlappingObjects.write[p_index].state = OVERLAP_STATE_INSIDE;
- }
-}
-
void AreaBullet::set_param(PhysicsServer3D::AreaParameter p_param, const Variant &p_value) {
switch (p_param) {
case PhysicsServer3D::AREA_PARAM_GRAVITY:
diff --git a/modules/bullet/area_bullet.h b/modules/bullet/area_bullet.h
index 4d9227c31a..3bff364cc1 100644
--- a/modules/bullet/area_bullet.h
+++ b/modules/bullet/area_bullet.h
@@ -43,8 +43,6 @@
class btGhostObject;
class AreaBullet : public RigidCollisionObjectBullet {
- friend void SpaceBullet::check_ghost_overlaps();
-
public:
struct InOutEventCallback {
Callable event_callback;
@@ -59,21 +57,19 @@ public:
OVERLAP_STATE_EXIT // Mark ended overlaps
};
- struct OverlappingObjectData {
- CollisionObjectBullet *object = nullptr;
- OverlapState state = OVERLAP_STATE_ENTER;
-
- OverlappingObjectData() {}
- OverlappingObjectData(CollisionObjectBullet *p_object, OverlapState p_state) :
- object(p_object),
- state(p_state) {}
- OverlappingObjectData(const OverlappingObjectData &other) {
- operator=(other);
- }
- void operator=(const OverlappingObjectData &other) {
- object = other.object;
- state = other.state;
- }
+ struct OverlappingShapeData {
+ CollisionObjectBullet *other_object = nullptr;
+ OverlapState state = OVERLAP_STATE_DIRTY;
+ uint32_t other_shape_id = 0;
+ uint32_t our_shape_id = 0;
+
+ OverlappingShapeData() {}
+
+ OverlappingShapeData(CollisionObjectBullet *p_other_object, OverlapState p_state, uint32_t p_other_shape_id, uint32_t p_our_shape_id) :
+ other_object(p_other_object),
+ state(p_state),
+ other_shape_id(p_other_shape_id),
+ our_shape_id(p_our_shape_id) {}
};
private:
@@ -82,7 +78,9 @@ private:
Variant *call_event_res_ptr[5] = {};
btGhostObject *btGhost = nullptr;
- Vector<OverlappingObjectData> overlappingObjects;
+ Vector<OverlappingShapeData> overlapping_shapes;
+ int _overlapping_shape_count(CollisionObjectBullet *p_other_object);
+ int _find_overlapping_shape(CollisionObjectBullet *p_other_object, uint32_t p_other_shape_id, uint32_t p_our_shape_id);
bool monitorable = true;
PhysicsServer3D::AreaSpaceOverrideMode spOv_mode = PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED;
@@ -104,7 +102,6 @@ public:
~AreaBullet();
_FORCE_INLINE_ btGhostObject *get_bt_ghost() const { return btGhost; }
- int find_overlapping_object(CollisionObjectBullet *p_colObj);
void set_monitorable(bool p_monitorable);
_FORCE_INLINE_ bool is_monitorable() const { return monitorable; }
@@ -143,20 +140,18 @@ public:
virtual void set_space(SpaceBullet *p_space);
virtual void dispatch_callbacks();
- void call_event(CollisionObjectBullet *p_otherObject, PhysicsServer3D::AreaBodyStatus p_status);
- void scratch();
-
- void clear_overlaps(bool p_notify);
- // Dispatch the callbacks and removes from overlapping list
- void remove_overlap(CollisionObjectBullet *p_object, bool p_notify);
+ void call_event(const OverlappingShapeData &p_overlapping_shape, PhysicsServer3D::AreaBodyStatus p_status);
virtual void on_collision_filters_change();
virtual void on_collision_checker_start() {}
virtual void on_collision_checker_end() { updated = false; }
- void add_overlap(CollisionObjectBullet *p_otherObject);
- void put_overlap_as_exit(int p_index);
- void put_overlap_as_inside(int p_index);
+ void mark_all_overlaps_dirty();
+ void mark_object_overlaps_inside(CollisionObjectBullet *p_other_object);
+ void set_overlap(CollisionObjectBullet *p_other_object, uint32_t p_other_shape_id, uint32_t p_our_shape_id);
+ void mark_all_dirty_overlaps_as_exit();
+ void remove_object_overlaps(CollisionObjectBullet *p_object);
+ void clear_overlaps();
void set_param(PhysicsServer3D::AreaParameter p_param, const Variant &p_value);
Variant get_param(PhysicsServer3D::AreaParameter p_param) const;
diff --git a/modules/bullet/collision_object_bullet.cpp b/modules/bullet/collision_object_bullet.cpp
index afd8cf4bf4..987a45ad5f 100644
--- a/modules/bullet/collision_object_bullet.cpp
+++ b/modules/bullet/collision_object_bullet.cpp
@@ -93,11 +93,9 @@ CollisionObjectBullet::CollisionObjectBullet(Type p_type) :
type(p_type) {}
CollisionObjectBullet::~CollisionObjectBullet() {
- // Remove all overlapping, notify is not required since godot take care of it
- for (int i = areasOverlapped.size() - 1; 0 <= i; --i) {
- areasOverlapped[i]->remove_overlap(this, /*Notify*/ false);
+ for (int i = 0; i < areasOverlapped.size(); i++) {
+ areasOverlapped[i]->remove_object_overlaps(this);
}
-
destroyBulletCollisionObject();
}
@@ -178,7 +176,9 @@ bool CollisionObjectBullet::is_collisions_response_enabled() {
}
void CollisionObjectBullet::notify_new_overlap(AreaBullet *p_area) {
- areasOverlapped.push_back(p_area);
+ if (areasOverlapped.find(p_area) == -1) {
+ areasOverlapped.push_back(p_area);
+ }
}
void CollisionObjectBullet::on_exit_area(AreaBullet *p_area) {
diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp
index bf47127877..7aa3815c94 100644
--- a/modules/bullet/space_bullet.cpp
+++ b/modules/bullet/space_bullet.cpp
@@ -662,101 +662,77 @@ void SpaceBullet::destroy_world() {
}
void SpaceBullet::check_ghost_overlaps() {
- /// Algorithm support variables
- btCollisionShape *other_body_shape;
- btConvexShape *area_shape;
- btGjkPairDetector::ClosestPointInput gjk_input;
- AreaBullet *area;
- int x(-1), i(-1), y(-1), z(-1), indexOverlap(-1);
-
- /// For each areas
- for (x = areas.size() - 1; 0 <= x; --x) {
- area = areas[x];
-
- btVector3 area_scale(area->get_bt_body_scale());
-
+ // For each area
+ for (int area_idx = 0; area_idx < areas.size(); area_idx++) {
+ AreaBullet *area = areas[area_idx];
if (!area->is_monitoring()) {
continue;
}
- /// 1. Reset all states
- for (i = area->overlappingObjects.size() - 1; 0 <= i; --i) {
- AreaBullet::OverlappingObjectData &otherObj = area->overlappingObjects.write[i];
- // This check prevent the overwrite of ENTER state
- // if this function is called more times before dispatchCallbacks
- if (otherObj.state != AreaBullet::OVERLAP_STATE_ENTER) {
- otherObj.state = AreaBullet::OVERLAP_STATE_DIRTY;
- }
- }
+ btGhostObject *bt_ghost = area->get_bt_ghost();
+ const btTransform &area_transform = area->get_transform__bullet();
+ const btVector3 &area_scale(area->get_bt_body_scale());
- /// 2. Check all overlapping objects using GJK
+ // Mark all current overlapping shapes dirty.
+ area->mark_all_overlaps_dirty();
- const btAlignedObjectArray<btCollisionObject *> ghostOverlaps = area->get_bt_ghost()->getOverlappingPairs();
+ // Broadphase
+ const btAlignedObjectArray<btCollisionObject *> overlapping_pairs = bt_ghost->getOverlappingPairs();
+ // Narrowphase
+ for (int pair_idx = 0; pair_idx < overlapping_pairs.size(); pair_idx++) {
+ btCollisionObject *other_bt_collision_object = overlapping_pairs[pair_idx];
+ RigidCollisionObjectBullet *other_object = static_cast<RigidCollisionObjectBullet *>(other_bt_collision_object->getUserPointer());
+ const btTransform &other_transform = other_object->get_transform__bullet();
+ const btVector3 &other_scale(other_object->get_bt_body_scale());
- // For each overlapping
- for (i = ghostOverlaps.size() - 1; 0 <= i; --i) {
- bool hasOverlap = false;
- btCollisionObject *overlapped_bt_co = ghostOverlaps[i];
- RigidCollisionObjectBullet *otherObject = static_cast<RigidCollisionObjectBullet *>(overlapped_bt_co->getUserPointer());
- btVector3 other_body_scale(otherObject->get_bt_body_scale());
-
- if (!area->is_updated() && !otherObject->is_updated()) {
- hasOverlap = -1 != area->find_overlapping_object(otherObject);
- goto collision_found;
+ if (!area->is_updated() && !other_object->is_updated()) {
+ area->mark_object_overlaps_inside(other_object);
+ continue;
}
- if (overlapped_bt_co->getUserIndex() == CollisionObjectBullet::TYPE_AREA) {
- if (!static_cast<AreaBullet *>(overlapped_bt_co->getUserPointer())->is_monitorable()) {
+ if (other_bt_collision_object->getUserIndex() == CollisionObjectBullet::TYPE_AREA) {
+ if (!static_cast<AreaBullet *>(other_bt_collision_object->getUserPointer())->is_monitorable()) {
continue;
}
- } else if (overlapped_bt_co->getUserIndex() != CollisionObjectBullet::TYPE_RIGID_BODY) {
+ } else if (other_bt_collision_object->getUserIndex() != CollisionObjectBullet::TYPE_RIGID_BODY) {
continue;
}
// For each area shape
- for (y = area->get_shape_count() - 1; 0 <= y; --y) {
- if (!area->get_bt_shape(y)->isConvex()) {
+ for (int our_shape_id = 0; our_shape_id < area->get_shape_count(); our_shape_id++) {
+ btCollisionShape *area_shape = area->get_bt_shape(our_shape_id);
+ if (!area_shape->isConvex()) {
continue;
}
+ btConvexShape *area_convex_shape = static_cast<btConvexShape *>(area_shape);
- btTransform area_shape_treansform(area->get_bt_shape_transform(y));
- area_shape_treansform.getOrigin() *= area_scale;
-
- gjk_input.m_transformA =
- area->get_transform__bullet() *
- area_shape_treansform;
-
- area_shape = static_cast<btConvexShape *>(area->get_bt_shape(y));
+ btTransform area_shape_transform(area->get_bt_shape_transform(our_shape_id));
+ area_shape_transform.getOrigin() *= area_scale;
+ btGjkPairDetector::ClosestPointInput gjk_input;
+ gjk_input.m_transformA = area_transform * area_shape_transform;
// For each other object shape
- for (z = otherObject->get_shape_count() - 1; 0 <= z; --z) {
- other_body_shape = static_cast<btCollisionShape *>(otherObject->get_bt_shape(z));
-
- btTransform other_shape_transform(otherObject->get_bt_shape_transform(z));
- other_shape_transform.getOrigin() *= other_body_scale;
-
- gjk_input.m_transformB =
- otherObject->get_transform__bullet() *
- other_shape_transform;
+ for (int other_shape_id = 0; other_shape_id < other_object->get_shape_count(); other_shape_id++) {
+ btCollisionShape *other_shape = other_object->get_bt_shape(other_shape_id);
+ btTransform other_shape_transform(other_object->get_bt_shape_transform(other_shape_id));
+ other_shape_transform.getOrigin() *= other_scale;
+ gjk_input.m_transformB = other_transform * other_shape_transform;
- if (other_body_shape->isConvex()) {
+ if (other_shape->isConvex()) {
btPointCollector result;
btGjkPairDetector gjk_pair_detector(
- area_shape,
- static_cast<btConvexShape *>(other_body_shape),
+ area_convex_shape,
+ static_cast<btConvexShape *>(other_shape),
gjk_simplex_solver,
gjk_epa_pen_solver);
- gjk_pair_detector.getClosestPoints(gjk_input, result, nullptr);
- if (0 >= result.m_distance) {
- hasOverlap = true;
- goto collision_found;
+ gjk_pair_detector.getClosestPoints(gjk_input, result, nullptr);
+ if (result.m_distance <= 0) {
+ area->set_overlap(other_object, other_shape_id, our_shape_id);
}
-
- } else {
- btCollisionObjectWrapper obA(nullptr, area_shape, area->get_bt_ghost(), gjk_input.m_transformA, -1, y);
- btCollisionObjectWrapper obB(nullptr, other_body_shape, otherObject->get_bt_collision_object(), gjk_input.m_transformB, -1, z);
-
+ } else { // Other shape is not convex.
+ btCollisionObjectWrapper obA(nullptr, area_convex_shape, bt_ghost, gjk_input.m_transformA, -1, our_shape_id);
+ btCollisionObjectWrapper obB(nullptr, other_shape, other_bt_collision_object, gjk_input.m_transformB, -1, other_shape_id);
btCollisionAlgorithm *algorithm = dispatcher->findAlgorithm(&obA, &obB, nullptr, BT_CONTACT_POINT_ALGORITHMS);
if (!algorithm) {
@@ -765,42 +741,20 @@ void SpaceBullet::check_ghost_overlaps() {
GodotDeepPenetrationContactResultCallback contactPointResult(&obA, &obB);
algorithm->processCollision(&obA, &obB, dynamicsWorld->getDispatchInfo(), &contactPointResult);
-
algorithm->~btCollisionAlgorithm();
dispatcher->freeCollisionAlgorithm(algorithm);
if (contactPointResult.hasHit()) {
- hasOverlap = true;
- goto collision_found;
+ area->set_overlap(other_object, our_shape_id, other_shape_id);
}
}
+ } // End for each other object shape
+ } // End for each area shape
+ } // End for each overlapping pair
- } // ~For each other object shape
- } // ~For each area shape
-
- collision_found:
- if (!hasOverlap) {
- continue;
- }
-
- indexOverlap = area->find_overlapping_object(otherObject);
- if (-1 == indexOverlap) {
- // Not found
- area->add_overlap(otherObject);
- } else {
- // Found
- area->put_overlap_as_inside(indexOverlap);
- }
- }
-
- /// 3. Remove not overlapping
- for (i = area->overlappingObjects.size() - 1; 0 <= i; --i) {
- // If the overlap has DIRTY state it means that it's no more overlapping
- if (area->overlappingObjects[i].state == AreaBullet::OVERLAP_STATE_DIRTY) {
- area->put_overlap_as_exit(i);
- }
- }
- }
+ // All overlapping shapes still marked dirty must have exited.
+ area->mark_all_dirty_overlaps_as_exit();
+ } // End for each area
}
void SpaceBullet::check_body_collision() {
diff --git a/modules/tinyexr/SCsub b/modules/tinyexr/SCsub
index 30bde96fb4..bf9242cc16 100644
--- a/modules/tinyexr/SCsub
+++ b/modules/tinyexr/SCsub
@@ -20,6 +20,9 @@ env_tinyexr.Prepend(CPPPATH=[thirdparty_dir])
# Enable threaded loading with C++11.
env_tinyexr.Append(CPPDEFINES=["TINYEXR_USE_THREAD"])
+# miniz is an external dependency, we could add it but we can instead rely
+# on our existing bundled zlib.
+env_tinyexr.Append(CPPDEFINES=[("TINYEXR_USE_MINIZ", 0)])
env_thirdparty = env_tinyexr.Clone()
env_thirdparty.disable_warnings()
diff --git a/modules/tinyexr/image_loader_tinyexr.cpp b/modules/tinyexr/image_loader_tinyexr.cpp
index eb7a8597e6..6c4c06aab0 100644
--- a/modules/tinyexr/image_loader_tinyexr.cpp
+++ b/modules/tinyexr/image_loader_tinyexr.cpp
@@ -33,6 +33,8 @@
#include "core/os/os.h"
#include "core/string/print_string.h"
+#include <zlib.h> // Should come before including tinyexr.
+
#include "thirdparty/tinyexr/tinyexr.h"
Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) {
diff --git a/modules/tinyexr/image_saver_tinyexr.cpp b/modules/tinyexr/image_saver_tinyexr.cpp
index 6a2fb0f666..f64acf8395 100644
--- a/modules/tinyexr/image_saver_tinyexr.cpp
+++ b/modules/tinyexr/image_saver_tinyexr.cpp
@@ -31,6 +31,8 @@
#include "image_saver_tinyexr.h"
#include "core/math/math_funcs.h"
+#include <zlib.h> // Should come before including tinyexr.
+
#include "thirdparty/tinyexr/tinyexr.h"
static bool is_supported_format(Image::Format p_format) {
diff --git a/modules/webp/SCsub b/modules/webp/SCsub
index 4c0c2f7893..80d62400c8 100644
--- a/modules/webp/SCsub
+++ b/modules/webp/SCsub
@@ -67,6 +67,7 @@ if env["builtin_libwebp"]:
"dsp/lossless_msa.c",
"dsp/lossless_neon.c",
"dsp/lossless_sse2.c",
+ "dsp/lossless_sse41.c",
"dsp/rescaler.c",
"dsp/rescaler_mips32.c",
"dsp/rescaler_mips_dsp_r2.c",
diff --git a/modules/websocket/SCsub b/modules/websocket/SCsub
index 4c022c43cf..63c941c4a8 100644
--- a/modules/websocket/SCsub
+++ b/modules/websocket/SCsub
@@ -18,12 +18,11 @@ elif env["builtin_wslay"]:
"wslay_net.c",
"wslay_event.c",
"wslay_queue.c",
- "wslay_stack.c",
"wslay_frame.c",
]
thirdparty_sources = [thirdparty_dir + s for s in thirdparty_sources]
- env_ws.Prepend(CPPPATH=[thirdparty_dir + "includes/"])
+ env_ws.Prepend(CPPPATH=[thirdparty_dir])
env_ws.Append(CPPDEFINES=["HAVE_CONFIG_H"])
if env["platform"] == "windows" or env["platform"] == "uwp":
diff --git a/servers/physics_2d/godot_area_2d.cpp b/servers/physics_2d/godot_area_2d.cpp
index fb9d38e7ea..c4060615c9 100644
--- a/servers/physics_2d/godot_area_2d.cpp
+++ b/servers/physics_2d/godot_area_2d.cpp
@@ -213,6 +213,7 @@ void GodotArea2D::set_monitorable(bool p_monitorable) {
monitorable = p_monitorable;
_set_static(!monitorable);
+ _shapes_changed();
}
void GodotArea2D::call_queries() {
diff --git a/servers/physics_2d/godot_area_pair_2d.cpp b/servers/physics_2d/godot_area_pair_2d.cpp
index a98513004d..bde22aab11 100644
--- a/servers/physics_2d/godot_area_pair_2d.cpp
+++ b/servers/physics_2d/godot_area_pair_2d.cpp
@@ -128,7 +128,7 @@ bool GodotArea2Pair2D::setup(real_t p_step) {
process_collision_a = false;
if (result_a != colliding_a) {
- if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) {
+ if (area_a->has_area_monitor_callback() && area_b_monitorable) {
process_collision_a = true;
process_collision = true;
}
@@ -137,7 +137,7 @@ bool GodotArea2Pair2D::setup(real_t p_step) {
process_collision_b = false;
if (result_b != colliding_b) {
- if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) {
+ if (area_b->has_area_monitor_callback() && area_a_monitorable) {
process_collision_b = true;
process_collision = true;
}
@@ -176,19 +176,21 @@ GodotArea2Pair2D::GodotArea2Pair2D(GodotArea2D *p_area_a, int p_shape_a, GodotAr
area_b = p_area_b;
shape_a = p_shape_a;
shape_b = p_shape_b;
+ area_a_monitorable = area_a->is_monitorable();
+ area_b_monitorable = area_b->is_monitorable();
area_a->add_constraint(this);
area_b->add_constraint(this);
}
GodotArea2Pair2D::~GodotArea2Pair2D() {
if (colliding_a) {
- if (area_a->has_area_monitor_callback()) {
+ if (area_a->has_area_monitor_callback() && area_b_monitorable) {
area_a->remove_area_from_query(area_b, shape_b, shape_a);
}
}
if (colliding_b) {
- if (area_b->has_area_monitor_callback()) {
+ if (area_b->has_area_monitor_callback() && area_a_monitorable) {
area_b->remove_area_from_query(area_a, shape_a, shape_b);
}
}
diff --git a/servers/physics_2d/godot_area_pair_2d.h b/servers/physics_2d/godot_area_pair_2d.h
index 45bd3df1ed..f1290a27d0 100644
--- a/servers/physics_2d/godot_area_pair_2d.h
+++ b/servers/physics_2d/godot_area_pair_2d.h
@@ -62,6 +62,8 @@ class GodotArea2Pair2D : public GodotConstraint2D {
bool colliding_b = false;
bool process_collision_a = false;
bool process_collision_b = false;
+ bool area_a_monitorable;
+ bool area_b_monitorable;
public:
virtual bool setup(real_t p_step) override;
diff --git a/servers/physics_3d/godot_area_3d.cpp b/servers/physics_3d/godot_area_3d.cpp
index 9cdad069fe..d4e14b8d85 100644
--- a/servers/physics_3d/godot_area_3d.cpp
+++ b/servers/physics_3d/godot_area_3d.cpp
@@ -242,6 +242,7 @@ void GodotArea3D::set_monitorable(bool p_monitorable) {
monitorable = p_monitorable;
_set_static(!monitorable);
+ _shapes_changed();
}
void GodotArea3D::call_queries() {
diff --git a/servers/physics_3d/godot_area_pair_3d.cpp b/servers/physics_3d/godot_area_pair_3d.cpp
index d3623178d5..58188565e3 100644
--- a/servers/physics_3d/godot_area_pair_3d.cpp
+++ b/servers/physics_3d/godot_area_pair_3d.cpp
@@ -129,7 +129,7 @@ bool GodotArea2Pair3D::setup(real_t p_step) {
process_collision_a = false;
if (result_a != colliding_a) {
- if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) {
+ if (area_a->has_area_monitor_callback() && area_b_monitorable) {
process_collision_a = true;
process_collision = true;
}
@@ -138,7 +138,7 @@ bool GodotArea2Pair3D::setup(real_t p_step) {
process_collision_b = false;
if (result_b != colliding_b) {
- if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) {
+ if (area_b->has_area_monitor_callback() && area_a_monitorable) {
process_collision_b = true;
process_collision = true;
}
@@ -177,19 +177,21 @@ GodotArea2Pair3D::GodotArea2Pair3D(GodotArea3D *p_area_a, int p_shape_a, GodotAr
area_b = p_area_b;
shape_a = p_shape_a;
shape_b = p_shape_b;
+ area_a_monitorable = area_a->is_monitorable();
+ area_b_monitorable = area_b->is_monitorable();
area_a->add_constraint(this);
area_b->add_constraint(this);
}
GodotArea2Pair3D::~GodotArea2Pair3D() {
if (colliding_a) {
- if (area_a->has_area_monitor_callback()) {
+ if (area_a->has_area_monitor_callback() && area_b_monitorable) {
area_a->remove_area_from_query(area_b, shape_b, shape_a);
}
}
if (colliding_b) {
- if (area_b->has_area_monitor_callback()) {
+ if (area_b->has_area_monitor_callback() && area_a_monitorable) {
area_b->remove_area_from_query(area_a, shape_a, shape_b);
}
}
diff --git a/servers/physics_3d/godot_area_pair_3d.h b/servers/physics_3d/godot_area_pair_3d.h
index 16175e9fa8..4237e7722e 100644
--- a/servers/physics_3d/godot_area_pair_3d.h
+++ b/servers/physics_3d/godot_area_pair_3d.h
@@ -63,6 +63,8 @@ class GodotArea2Pair3D : public GodotConstraint3D {
bool colliding_b = false;
bool process_collision_a = false;
bool process_collision_b = false;
+ bool area_a_monitorable;
+ bool area_b_monitorable;
public:
virtual bool setup(real_t p_step) override;
diff --git a/thirdparty/README.md b/thirdparty/README.md
index e1c0aaec89..18da4d6a63 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -176,14 +176,14 @@ Files extracted from upstream source:
## graphite
- Upstream: https://github.com/silnrsi/graphite
-- Version: 1.3.14 (92f59dcc52f73ce747f1cdc831579ed2546884aa, 2020)
+- Version: 1.3.14 (80c52493ef42e6fe605a69dcddd2a691cd8a1380, 2021)
- License: MPL-2.0
Files extracted from upstream source:
- the `include` folder
-- the `src` folder
-- `COPYING`, `ChangeLog`
+- the `src` folder (minus `CMakeLists.txt` and `files.mk`)
+- `COPYING`
## harfbuzz
@@ -235,14 +235,14 @@ Files extracted from upstream source:
## libogg
- Upstream: https://www.xiph.org/ogg
-- Version: git (c8fca6b4a02d695b1ceea39b330d4406001c03ed, 2019)
+- Version: 1.3.5 (e1774cd77f471443541596e09078e78fdc342e4f, 2021)
- License: BSD-3-Clause
Files extracted from upstream source:
- `src/*.{c,h}`
-- `include/ogg/*.h` in ogg/
-- COPYING
+- `include/ogg/*.h` in `ogg/` (run `configure` to generate `config_types.h`)
+- `COPYING`
## libpng
@@ -279,26 +279,26 @@ on top of the 1.1.1 source (not included in any stable release yet).
## libvorbis
- Upstream: https://www.xiph.org/vorbis
-- Version: 1.3.6 (2018)
+- Version: 1.3.7 (0657aee69dec8508a0011f47f3b69d7538e9d262, 2020)
- License: BSD-3-Clause
Files extracted from upstream source:
-- `src/*` except from: `lookups.pl`, `Makefile.*`
-- `include/vorbis/*.h` as vorbis/
-- COPYING
+- `lib/*` except from: `lookups.pl`, `Makefile.*`
+- `include/vorbis/*.h` as `vorbis/`
+- `COPYING`
## libwebp
- Upstream: https://chromium.googlesource.com/webm/libwebp/
-- Version: 1.1.0 (d7844e9762b61c9638c263657bd49e1690184832, 2020)
+- Version: 1.2.1 (9ce5843dbabcfd3f7c39ec7ceba9cbeb213cbfdf, 2021)
- License: BSD-3-Clause
Files extracted from upstream source:
-- `src/*` except from: .am, .rc and .in files
-- AUTHORS, COPYING, PATENTS
+- `src/*` except from: `.am`, `.rc` and `.in` files
+- `AUTHORS`, `COPYING`, `PATENTS`
Important: The files `utils/bit_reader_utils.{c,h}` have Godot-made
changes to ensure they build for Javascript/HTML5. Those
@@ -503,7 +503,7 @@ Patch files are provided in `oidn/patches/`.
## pcre2
- Upstream: http://www.pcre.org
-- Version: 10.36 (r1288, 2020)
+- Version: 10.39 (35fee4193b852cb504892352bd0155de10809889, 2021)
- License: BSD-3-Clause
Files extracted from upstream source:
@@ -596,18 +596,21 @@ comments and a patch is provided in the squish/ folder.
## tinyexr
- Upstream: https://github.com/syoyo/tinyexr
-- Version: 1.0.0 (e4b7840d9448b7d57a88384ce26143004f3c0c71, 2020)
+- Version: 1.0.1 (67010eae802211202d0797f4df2b809f4ba7442c, 2021)
- License: BSD-3-Clause
Files extracted from upstream source:
- `tinyexr.{cc,h}`
+The `tinyexr.cc` file was modified to include `zlib.h` which we provide,
+instead of `miniz.h` as an external dependency.
+
## vhacd
- Upstream: https://github.com/kmammou/v-hacd
-- Version: git (b07958e18e01d504e3af80eeaeb9f033226533d7, 2019)
+- Version: git (1a49edf29c69039df15286181f2f27e17ceb9aef, 2020)
- License: BSD-3-Clause
Files extracted from upstream source:
@@ -667,25 +670,29 @@ Patches in the `patches` directory should be re-applied after updates.
## wslay
- Upstream: https://github.com/tatsuhiro-t/wslay
-- Version: 1.1.1 (c9a84aa6df8512584c77c8cd15be9536b89c35aa, 2020)
+- Version: 1.1.1+git (45d22583b488f79d5a4e598cc7675c191c5ab53f, 2021)
- License: MIT
File extracted from upstream release tarball:
-- All `*.c` and `*.h` in `lib/` and `lib/includes/`
-- `wslay.h` has a small Godot addition to fix MSVC build.
- See `thirdparty/wslay/msvcfix.diff`
+- Run `cmake .` to generate `config.h` and `wslayver.h`.
+ Contents might need tweaking for Godot, review diff.
+- All `*.c` and `*.h` files from `lib/`
+- All `*.h` in `lib/includes/wslay/` as `wslay/`
+- `wslay/wslay.h` has a small Godot addition to fix MSVC build.
+ See `patches/msvcfix.diff`
+- `COPYING`
## xatlas
- Upstream: https://github.com/jpcy/xatlas
-- Version: git (5571fc7ef0d06832947c0a935ccdcf083f7a9264, 2020)
+- Version: git (ec707faeac3b95e6b416076a9509718cce105b6a, 2021)
- License: MIT
Files extracted from upstream source:
-- `xatlas.{cpp,h}`
+- `source/xatlas/xatlas.{cpp,h}`
- `LICENSE`
@@ -703,11 +710,11 @@ Files extracted from upstream source:
## zstd
- Upstream: https://github.com/facebook/zstd
-- Version: 1.4.8 (97a3da1df009d4dc67251de0c4b1c9d7fe286fc1, 2020)
+- Version: 1.5.0 (a488ba114ec17ea1054b9057c26a046fc122b3b6, 2021)
- License: BSD-3-Clause
Files extracted from upstream source:
-- lib/{common/,compress/,decompress/,zstd.h}
-- LICENSE
+- `lib/{common/,compress/,decompress/,zstd.h,zstd_errors.h}`
+- `LICENSE`
diff --git a/thirdparty/certs/ca-certificates.crt b/thirdparty/certs/ca-certificates.crt
index 7d5ea3bef1..7f89e81d01 100644
--- a/thirdparty/certs/ca-certificates.crt
+++ b/thirdparty/certs/ca-certificates.crt
@@ -1,7 +1,7 @@
##
## Bundle of CA Root Certificates
##
-## Certificate data from Mozilla as of: Mon Jul 5 21:36:52 2021 GMT
+## Certificate data from Mozilla as of: Mon Nov 1 15:39:58 2021 GMT
##
## This is a bundle of X.509 certificates of public Certificate Authorities
## (CA). These were automatically extracted from Mozilla's root certificates
@@ -14,7 +14,7 @@
## Just configure this file as the SSLCACertificateFile.
##
## Conversion done with mk-ca-bundle.pl version 1.28.
-## SHA256: c8f6733d1ff4e6a4769c182971a1234f95ae079247a9c439a13423fe8ba5c24f
+## SHA256: bb36818a81feaa4cca61101e6d6276cd09e972efcb08112dfed846918ca41d7f
##
@@ -381,26 +381,6 @@ mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K
-----END CERTIFICATE-----
-DST Root CA X3
-==============
------BEGIN CERTIFICATE-----
-MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQK
-ExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4X
-DTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1
-cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQAD
-ggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmT
-rE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9
-UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRy
-xXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40d
-utolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0T
-AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQ
-MA0GCSqGSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikug
-dB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjE
-GB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bw
-RLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubS
-fZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
------END CERTIFICATE-----
-
SwissSign Gold CA - G2
======================
-----BEGIN CERTIFICATE-----
@@ -2713,7 +2693,8 @@ CBeQyh+KTOgNG3qxrdWBCUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7
jHvrZQnD+JbNR6iC8hZVdyR+EhCVBCyj
-----END CERTIFICATE-----
-# emSign Root CA - C1
+emSign Root CA - C1
+===================
-----BEGIN CERTIFICATE-----
MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkGA1UEBhMCVVMx
EzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNp
@@ -2733,7 +2714,8 @@ wC68AivTxEDkigcxHpvOJpkT+xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQ
BmIMMMAVSKeoWXzhriKi4gp6D/piq1JM4fHfyr6DDUI=
-----END CERTIFICATE-----
-# emSign ECC Root CA - C3
+emSign ECC Root CA - C3
+=======================
-----BEGIN CERTIFICATE-----
MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQGEwJVUzETMBEG
A1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMxIDAeBgNVBAMTF2VtU2lnbiBF
@@ -2747,7 +2729,8 @@ MGUCMQC02C8Cif22TGK6Q04ThHK1rt0c3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwU
ZOR8loMRnLDRWmFLpg9J0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ==
-----END CERTIFICATE-----
-# Hongkong Post Root CA 3
+Hongkong Post Root CA 3
+=======================
-----BEGIN CERTIFICATE-----
MIIFzzCCA7egAwIBAgIUCBZfikyl7ADJk0DfxMauI7gcWqQwDQYJKoZIhvcNAQELBQAwbzELMAkG
A1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJSG9uZyBLb25nMRYwFAYDVQQK
@@ -2778,7 +2761,8 @@ hcErulWuBurQB7Lcq9CClnXO0lD+mefPL5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB
dBb9HxEGmpv0
-----END CERTIFICATE-----
-# Entrust Root Certification Authority - G4
+Entrust Root Certification Authority - G4
+=========================================
-----BEGIN CERTIFICATE-----
MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAwgb4xCzAJBgNV
BAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3Qu
@@ -2811,7 +2795,8 @@ JOgc47OlIQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk5F6G
kcpG2om3PVODLAgfi49T3f+sHw==
-----END CERTIFICATE-----
-# Microsoft ECC Root Certificate Authority 2017
+Microsoft ECC Root Certificate Authority 2017
+=============================================
-----BEGIN CERTIFICATE-----
MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV
UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNyb3NvZnQgRUND
@@ -2826,7 +2811,8 @@ Xu5gKcs68tvWMoQZP3zVL8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaR
eNtUjGUBiudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M=
-----END CERTIFICATE-----
-# Microsoft RSA Root Certificate Authority 2017
+Microsoft RSA Root Certificate Authority 2017
+=============================================
-----BEGIN CERTIFICATE-----
MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBlMQswCQYDVQQG
EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNyb3NvZnQg
@@ -2856,7 +2842,8 @@ c0QWbej09+CVgI+WXTik9KveCjCHk9hNAHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D
5KbvtwEwXlGjefVwaaZBRA+GsCyRxj3qrg+E
-----END CERTIFICATE-----
-# e-Szigno Root CA 2017
+e-Szigno Root CA 2017
+=====================
-----BEGIN CERTIFICATE-----
MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNVBAYTAkhVMREw
DwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRkLjEXMBUGA1UEYQwOVkFUSFUt
@@ -2871,7 +2858,8 @@ tVfd14pVCzbhhkT61NlojbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxO
svxyqltZ+efcMQ==
-----END CERTIFICATE-----
-# certSIGN Root CA G2
+certSIGN Root CA G2
+===================
-----BEGIN CERTIFICATE-----
MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNVBAYTAlJPMRQw
EgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04gUk9PVCBDQSBHMjAeFw0xNzAy
@@ -2899,7 +2887,8 @@ NMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE1LlSVHJ7liXMvGnjSG4N
0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MXQRBdJ3NghVdJIgc=
-----END CERTIFICATE-----
-# Trustwave Global Certification Authority
+Trustwave Global Certification Authority
+========================================
-----BEGIN CERTIFICATE-----
MIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJV
UzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2
@@ -2930,7 +2919,8 @@ Yj6RS8fZMXZC+fc8Y+wmjHMMfRod6qh8h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu
29FpHOTKyeC2nOnOcXHebD8WpHk=
-----END CERTIFICATE-----
-# Trustwave Global ECC P256 Certification Authority
+Trustwave Global ECC P256 Certification Authority
+=================================================
-----BEGIN CERTIFICATE-----
MIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYDVQQGEwJVUzER
MA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0d2F2ZSBI
@@ -2945,7 +2935,8 @@ P62jQzBBMA8GA1UdEwEB/wQFMAMBAf8wDwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUo0EGrJBt
RM4q3wghDDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7
-----END CERTIFICATE-----
-# Trustwave Global ECC P384 Certification Authority
+Trustwave Global ECC P384 Certification Authority
+=================================================
-----BEGIN CERTIFICATE-----
MIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYDVQQGEwJVUzER
MA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0d2F2ZSBI
@@ -2961,7 +2952,8 @@ ADBkAjA3AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsCMGcl
CrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVuSw==
-----END CERTIFICATE-----
-# NAVER Global Root Certification Authority
+NAVER Global Root Certification Authority
+=========================================
-----BEGIN CERTIFICATE-----
MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEMBQAwaTELMAkG
A1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRGT1JNIENvcnAuMTIwMAYDVQQD
@@ -2991,7 +2983,8 @@ I/hGoiLtk/bdmuYqh7GYVPEi92tF4+KOdh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmg
kpzNNIaRkPpkUZ3+/uul9XXeifdy
-----END CERTIFICATE-----
-# AC RAIZ FNMT-RCM SERVIDORES SEGUROS
+AC RAIZ FNMT-RCM SERVIDORES SEGUROS
+===================================
-----BEGIN CERTIFICATE-----
MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQswCQYDVQQGEwJF
UzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgwFgYDVQRhDA9WQVRFUy1RMjgy
@@ -3006,7 +2999,8 @@ SM49BAMDA2kAMGYCMQCuSuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoD
zBOQn5ICMQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJyv+c=
-----END CERTIFICATE-----
-# GlobalSign Root R46
+GlobalSign Root R46
+===================
-----BEGIN CERTIFICATE-----
MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUAMEYxCzAJBgNV
BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQDExNHbG9iYWxTaWduIFJv
@@ -3035,7 +3029,8 @@ DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3vouXsXgxT7PntgMTzlSdriVZzH81Xwj3
QEUxeCp6
-----END CERTIFICATE-----
-# GlobalSign Root E46
+GlobalSign Root E46
+===================
-----BEGIN CERTIFICATE-----
MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYxCzAJBgNVBAYT
AkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQDExNHbG9iYWxTaWduIFJvb3Qg
@@ -3049,7 +3044,8 @@ vLtoURMMA/cVi4RguYv/Uo7njLwcAjA8+RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+
CAezNIm8BZ/3Hobui3A=
-----END CERTIFICATE-----
-# GLOBALTRUST 2020
+GLOBALTRUST 2020
+================
-----BEGIN CERTIFICATE-----
MIIFgjCCA2qgAwIBAgILWku9WvtPilv6ZeUwDQYJKoZIhvcNAQELBQAwTTELMAkGA1UEBhMCQVQx
IzAhBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVT
@@ -3078,7 +3074,8 @@ YqYK6miyeUcGbvJXqBUzxvd4Sj1Ce2t+/vdG6tHrju+IaFvowdlxfv1k7/9nR4hYJS8+hge9+6jl
gqispdNpQ80xiEmEU5LAsTkbOYMBMMTyqfrQA71yN2BWHzZ8vTmR9W0Nv3vXkg==
-----END CERTIFICATE-----
-# ANF Secure Server Root CA
+ANF Secure Server Root CA
+=========================
-----BEGIN CERTIFICATE-----
MIIF7zCCA9egAwIBAgIIDdPjvGz5a7EwDQYJKoZIhvcNAQELBQAwgYQxEjAQBgNVBAUTCUc2MzI4
NzUxMDELMAkGA1UEBhMCRVMxJzAlBgNVBAoTHkFORiBBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lv
@@ -3109,7 +3106,8 @@ g77FGr8H6lnco4g175x2MjxNBiLOFeXdntiP2t7SxDnlF4HPOEfrf4htWRvfn0IUrn7PqLBmZdo3
r5+qPeoott7VMVgWglvquxl1AnMaykgaIZOQCo6ThKd9OyMYkomgjaw=
-----END CERTIFICATE-----
-# Certum EC-384 CA
+Certum EC-384 CA
+================
-----BEGIN CERTIFICATE-----
MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQswCQYDVQQGEwJQ
TDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2Vy
@@ -3124,7 +3122,8 @@ ADBlAjADVS2m5hjEfO/JUG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0
QoSZ/6vnnvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k=
-----END CERTIFICATE-----
-# Certum Trusted Root CA
+Certum Trusted Root CA
+======================
-----BEGIN CERTIFICATE-----
MIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6MQswCQYDVQQG
EwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0g
@@ -3153,3 +3152,81 @@ WWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7DP78v3DSk+yshzWePS/Tj
OPQD8rv7gmsHINFSH5pkAnuYZttcTVoP0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZck
bxJF0WddCajJFdr60qZfE2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb
-----END CERTIFICATE-----
+
+TunTrust Root CA
+================
+-----BEGIN CERTIFICATE-----
+MIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQELBQAwYTELMAkG
+A1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUgQ2VydGlmaWNhdGlvbiBFbGVj
+dHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJvb3QgQ0EwHhcNMTkwNDI2MDg1NzU2WhcNNDQw
+NDI2MDg1NzU2WjBhMQswCQYDVQQGEwJUTjE3MDUGA1UECgwuQWdlbmNlIE5hdGlvbmFsZSBkZSBD
+ZXJ0aWZpY2F0aW9uIEVsZWN0cm9uaXF1ZTEZMBcGA1UEAwwQVHVuVHJ1c3QgUm9vdCBDQTCCAiIw
+DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMPN0/y9BFPdDCA61YguBUtB9YOCfvdZn56eY+hz
+2vYGqU8ftPkLHzmMmiDQfgbU7DTZhrx1W4eI8NLZ1KMKsmwb60ksPqxd2JQDoOw05TDENX37Jk0b
+bjBU2PWARZw5rZzJJQRNmpA+TkBuimvNKWfGzC3gdOgFVwpIUPp6Q9p+7FuaDmJ2/uqdHYVy7BG7
+NegfJ7/Boce7SBbdVtfMTqDhuazb1YMZGoXRlJfXyqNlC/M4+QKu3fZnz8k/9YosRxqZbwUN/dAd
+gjH8KcwAWJeRTIAAHDOFli/LQcKLEITDCSSJH7UP2dl3RxiSlGBcx5kDPP73lad9UKGAwqmDrViW
+VSHbhlnUr8a83YFuB9tgYv7sEG7aaAH0gxupPqJbI9dkxt/con3YS7qC0lH4Zr8GRuR5KiY2eY8f
+Tpkdso8MDhz/yV3A/ZAQprE38806JG60hZC/gLkMjNWb1sjxVj8agIl6qeIbMlEsPvLfe/ZdeikZ
+juXIvTZxi11Mwh0/rViizz1wTaZQmCXcI/m4WEEIcb9PuISgjwBUFfyRbVinljvrS5YnzWuioYas
+DXxU5mZMZl+QviGaAkYt5IPCgLnPSz7ofzwB7I9ezX/SKEIBlYrilz0QIX32nRzFNKHsLA4KUiwS
+VXAkPcvCFDVDXSdOvsC9qnyW5/yeYa1E0wCXAgMBAAGjYzBhMB0GA1UdDgQWBBQGmpsfU33x9aTI
+04Y+oXNZtPdEITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFAaamx9TffH1pMjThj6hc1m0
+90QhMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAqgVutt0Vyb+zxiD2BkewhpMl
+0425yAA/l/VSJ4hxyXT968pk21vvHl26v9Hr7lxpuhbI87mP0zYuQEkHDVneixCwSQXi/5E/S7fd
+Ao74gShczNxtr18UnH1YeA32gAm56Q6XKRm4t+v4FstVEuTGfbvE7Pi1HE4+Z7/FXxttbUcoqgRY
+YdZ2vyJ/0Adqp2RT8JeNnYA/u8EH22Wv5psymsNUk8QcCMNE+3tjEUPRahphanltkE8pjkcFwRJp
+adbGNjHh/PqAulxPxOu3Mqz4dWEX1xAZufHSCe96Qp1bWgvUxpVOKs7/B9dPfhgGiPEZtdmYu65x
+xBzndFlY7wyJz4sfdZMaBBSSSFCp61cpABbjNhzI+L/wM9VBD8TMPN3pM0MBkRArHtG5Xc0yGYuP
+jCB31yLEQtyEFpslbei0VXF/sHyz03FJuc9SpAQ/3D2gu68zngowYI7bnV2UqL1g52KAdoGDDIzM
+MEZJ4gzSqK/rYXHv5yJiqfdcZGyfFoxnNidF9Ql7v/YQCvGwjVRDjAS6oz/v4jXH+XTgbzRB0L9z
+ZVcg+ZtnemZoJE6AZb0QmQZZ8mWvuMZHu/2QeItBcy6vVR/cO5JyboTT0GFMDcx2V+IthSIVNg3r
+AZ3r2OvEhJn7wAzMMujjd9qDRIueVSjAi1jTkD5OGwDxFa2DK5o=
+-----END CERTIFICATE-----
+
+HARICA TLS RSA Root CA 2021
+===========================
+-----BEGIN CERTIFICATE-----
+MIIFpDCCA4ygAwIBAgIQOcqTHO9D88aOk8f0ZIk4fjANBgkqhkiG9w0BAQsFADBsMQswCQYDVQQG
+EwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u
+cyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBSU0EgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTEwNTUz
+OFoXDTQ1MDIxMzEwNTUzN1owbDELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRl
+bWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgUlNB
+IFJvb3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIvC569lmwVnlskN
+JLnQDmT8zuIkGCyEf3dRywQRNrhe7Wlxp57kJQmXZ8FHws+RFjZiPTgE4VGC/6zStGndLuwRo0Xu
+a2s7TL+MjaQenRG56Tj5eg4MmOIjHdFOY9TnuEFE+2uva9of08WRiFukiZLRgeaMOVig1mlDqa2Y
+Ulhu2wr7a89o+uOkXjpFc5gH6l8Cct4MpbOfrqkdtx2z/IpZ525yZa31MJQjB/OCFks1mJxTuy/K
+5FrZx40d/JiZ+yykgmvwKh+OC19xXFyuQnspiYHLA6OZyoieC0AJQTPb5lh6/a6ZcMBaD9YThnEv
+dmn8kN3bLW7R8pv1GmuebxWMevBLKKAiOIAkbDakO/IwkfN4E8/BPzWr8R0RI7VDIp4BkrcYAuUR
+0YLbFQDMYTfBKnya4dC6s1BG7oKsnTH4+yPiAwBIcKMJJnkVU2DzOFytOOqBAGMUuTNe3QvboEUH
+GjMJ+E20pwKmafTCWQWIZYVWrkvL4N48fS0ayOn7H6NhStYqE613TBoYm5EPWNgGVMWX+Ko/IIqm
+haZ39qb8HOLubpQzKoNQhArlT4b4UEV4AIHrW2jjJo3Me1xR9BQsQL4aYB16cmEdH2MtiKrOokWQ
+CPxrvrNQKlr9qEgYRtaQQJKQCoReaDH46+0N0x3GfZkYVVYnZS6NRcUk7M7jAgMBAAGjQjBAMA8G
+A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFApII6ZgpJIKM+qTW8VX6iVNvRLuMA4GA1UdDwEB/wQE
+AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAPpBIqm5iFSVmewzVjIuJndftTgfvnNAUX15QvWiWkKQU
+EapobQk1OUAJ2vQJLDSle1mESSmXdMgHHkdt8s4cUCbjnj1AUz/3f5Z2EMVGpdAgS1D0NTsY9FVq
+QRtHBmg8uwkIYtlfVUKqrFOFrJVWNlar5AWMxajaH6NpvVMPxP/cyuN+8kyIhkdGGvMA9YCRotxD
+QpSbIPDRzbLrLFPCU3hKTwSUQZqPJzLB5UkZv/HywouoCjkxKLR9YjYsTewfM7Z+d21+UPCfDtcR
+j88YxeMn/ibvBZ3PzzfF0HvaO7AWhAw6k9a+F9sPPg4ZeAnHqQJyIkv3N3a6dcSFA1pj1bF1BcK5
+vZStjBWZp5N99sXzqnTPBIWUmAD04vnKJGW/4GKvyMX6ssmeVkjaef2WdhW+o45WxLM0/L5H9MG0
+qPzVMIho7suuyWPEdr6sOBjhXlzPrjoiUevRi7PzKzMHVIf6tLITe7pTBGIBnfHAT+7hOtSLIBD6
+Alfm78ELt5BGnBkpjNxvoEppaZS3JGWg/6w/zgH7IS79aPib8qXPMThcFarmlwDB31qlpzmq6YR/
+PFGoOtmUW4y/Twhx5duoXNTSpv4Ao8YWxw/ogM4cKGR0GQjTQuPOAF1/sdwTsOEFy9EgqoZ0njnn
+kf3/W9b3raYvAwtt41dU63ZTGI0RmLo=
+-----END CERTIFICATE-----
+
+HARICA TLS ECC Root CA 2021
+===========================
+-----BEGIN CERTIFICATE-----
+MIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQswCQYDVQQGEwJH
+UjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBD
+QTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBFQ0MgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTExMDExMFoX
+DTQ1MDIxMzExMDEwOVowbDELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWlj
+IGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgRUNDIFJv
+b3QgQ0EgMjAyMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDgI/rGgltJ6rK9JOtDA4MM7KKrxcm1l
+AEeIhPyaJmuqS7psBAqIXhfyVYf8MLA04jRYVxqEU+kw2anylnTDUR9YSTHMmE5gEYd103KUkE+b
+ECUqqHgtvpBBWJAVcqeht6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUyRtTgRL+BNUW
+0aq8mm+3oJUZbsowDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2cAMGQCMBHervjcToiwqfAi
+rcJRQO9gcS3ujwLEXQNwSaSS6sUUiHCm0w2wqsosQJz76YJumgIwK0eaB8bRwoF8yguWGEEbo/Qw
+CZ61IygNnxS2PFOiTAZpffpskcYqSUXm7LcT4Tps
+-----END CERTIFICATE-----
diff --git a/thirdparty/graphite/ChangeLog b/thirdparty/graphite/ChangeLog
deleted file mode 100644
index e36110e1c1..0000000000
--- a/thirdparty/graphite/ChangeLog
+++ /dev/null
@@ -1,238 +0,0 @@
-1.3.14
- . Bug fixes
- . Allow features to be hidden (for aliases)
- . Move to python3
- . Rename doc files from .txt to .asc
-
-1.3.13
- . Resolve minor spacing issue in rtl non-overlap kerning
- . python3 for graphite.py
- . Better fuzzing
- . Better building on windows
-
-1.3.12
- . Graphite no longer does dumb rendering for fonts with no smarts
- . Segment caching code removed. Anything attempting to use the segment cache gets given a regular face instead
- . Add libfuzzer support
- . Builds now require C++11
- . Improvements to Windows 64 bit builds
- . Support different versions of python including 32 bit and python 3
- . Various minor bug fixes
-
-1.3.11
- . Fixes due to security review
- . Minor collision avoidance fixes
- . Fix LZ4 decompressor against high compression
-
-1.3.10
- . Address floating point build parameters to give consistent positioning results across platforms
- . Various bug fixes
-
-1.3.9
- . Add Collision COLL_ISSPACE to allow for visible spaces in collision avoidance
- . Add segment and pass direction information to tracing output
- . Bug fix rule length testing in 32-bit
- . Increase slanted margin distances for collision avoidance
- . Change kerning algorithm to simple outline expansion. Seems to make no visible difference.
- . Add trace2svg to test tools
-
-1.3.8
- . Various bug fixes arising from fuzzing
- . Fix regression that stopped piglatin from working
- . Make collision avoidance kerning give more regular results
- . Minor modification to clustering algorithm to handle variable width chars
-
-1.3.7
- . Bug fixes
- . Start to deprecate SegCache. This will be going away in a later release.
-
-1.3.6
- . Bug fixes
-
-1.3.5
- . Bug fixes
- . Security bug fix
- . Fix ARM misalignment problem
- . Track latest cmake
-
-1.3.4
- . Transition from Mercurial to Git
- . Bug fixes
- . Fix Collision Kerning ignoring some diacritics
- . Handle pass bits 16-31 to speed up fonts with > 16 passes
- . Various minor fuzz bug fixes
- . Make Coverity happy
- . Add GR_FALLTHROUGH macro for clang c++11
-
-1.3.3
- . Slight speed up in Collision Avoidance
- . Remove dead bidi code
- . Bug fixes
- . Between pass bidi reorderings and at the end
- . Decompressor fuzz bugs
- . Other fuzz bugs
-
-1.3.2
- . Remove full bidi. All segments are assumed to be single directioned.
- . Bug fixes:
- . Decompressor corner cases
- . Various fuzz bugs
-
-1.3.1
- . Deprecation warning: Full bidi support is about to be deprecated. Make contact
- if this impacts you.
- . Change compression block format slightly to conform to LZ4
- . Bug fixes:
- . Handle mono direction text with diacritics consistently. Fonts
- now see the direction they expect consistently and bidi now
- gives expected results.
- . Fixed lots of fuzz bugs
- . Coverity cleanups
- . Build now works for clang and/or asan and/or afl etc.
-
-1.3.0
- . Add collision avoidance
- . Shift Collider
- . Kern Collider
- . Octabox outlines and subboxes
- . Add compressed Silf and Glat table support
- . Bug fixes:
- . Stop loops forming in the child, sibling tree
- . Handle bidi mirroring correctly if no bidi occurring
-
-1.2.4
- . Face failure now has error code reporting via debug logging
- . can now call gr_start_logging(NULL, fname)
- . gr2fonttest --alltrace added
- . Format 14 table support
- . Not done. To be handled entirely in the compiler
- . Bidi support for Unicode 6.3 Isolating direction controls
- . Fonts no longer require a glyf/loca table. In such cases the bounding box is always 0.
- . Clang ASAN build support added for testing.
- . Handle out of memory sanely.
- . Documentation improvements
- . Bug fixes:
- . Enforce fonts having to store glyph attributes by monotonically increasing attribute number
- . zeropadding was not getting called on feature tags
- . automatic associations for unassociated characters
- . use direct engine on Mac
- . various extreme case reading 1 past the end errors fixed
- . remove tabs from sources so that it becomes readable again
-
-1.2.3
- . Bug fixes only:
- . fix byte swapping when testing cmap subtable lengths
- . work around armel compilation problems with conditional operators
- . fix pseudoglyph support for advance and bbox
-
-1.2.2
- . Add support for passKeySlot (makes Charis 2x faster) up to 32 passes
- . Add telemetry output to json if enabled in build GRAPHITE2_TELEMETRY
- . Shrink font memory footprint particularly in the fsm
- . Add -S to comparerenderer
- . Bug fixes:
- . Fix shift.x being reversed for rtl text
- . Fix faulty fallback justification
- . Fix bad cmap handling
- . Support compiling on old Solaris where bidi attributes clash with register names
- . Follow the crowd in using Windows.h
-
-1.2.1
- . Bug fixes:
- . Allow glyph reattachment
- . Allow signed glyph attributes
- . Various build problems with MacOS, old gcc versions, etc.
- . Various overrun read errors fixed
-
-1.2.0
- . API Changes:
- . Added Windows friendly gr_start_logging and gr_stop_logging, now per face
- . Added gr_make_face_with_ops, gr_make_face_with_seg_cache_and_ops
- . Added gr_make_font_with_ops
- . Added gr_face_is_char_supported
- . Added gr_face_info to give info to apps about face capabilities
- . Deprecated gr_make_face, gr_make_face_with_seg_cache, gr_make_font_with_advance_fn
- . Deprecated graphite_start_logging and graphite_stop_logging
- . These functions are stubbed now and do nothing, but do compile and link.
- . Bump API version to 3
- . Add C# wrapper to contrib
- . Handle justification information in a font and do something useful with it
- . Builds clang clean (has done for a while)
- . Bug fixes
- . Windows build and bug fixes
- . Add extra information to json debug output
- . Added windows build documentation
- . Added freetype sample code and test
-
-1.1.3
- . Default build has GRAPHITE2_COMPARE_RENDERER to OFF to reduce dependencies
- . Builds on Mac with clang
- . Debug output improvements
- . Tidy up perl wrappers
- . Fuzz tester improvements
- . Various bug fixes for bad font handling
-
-1.1.2
- . Support feature ids < 4 chars when space padded for inclusion in FF 14.
- . More fuzztesting and removal of causes of valgrind bad reads and sigabrts
- . Remove contrib/android into its own repo (http://hg.palaso.org/grandroid)
- . Update comparerenderer to latest harfbuzzng api
-
-1.1.1
- . Missing Log.h included
- . perl wrappers updated
-
-1.1.0
- . Refactored debug output to use json
- . Renamed VM_MACHINE_TYPE to GRAPHITE2_VM_TYPE
- . Renamed DISABLE_SEGCACHE to GRAPHITE2_NSEGCACE
- . Renamed DISBALE_FILE_FACE to GRAPHITE2_NFILEFACE
- . Renamed ENABLE_COMPARE_RENDERER to GRAPHTIE2_COMPARE_RENDERER
- . Renamed DOXYGEN_CONFIG to GRAPHITE2_DOXYGEN_CONFIG
- . Renamed GR2_CUSTOM_HEADER to GRAPHITE2_CUSTOM_HEADER
- . Renamed GR2_EXPORTING to GRAPHITE2_EXPORTING
- . Added GRAPHITE2_STATIC for static only builds
- . Added GRAPHITE2_NTRACING to compile out tracing code
- . Documented GRAPHITE2_{EXPORTING,STATIC,NTRACING} in hacking.txt
- . Bump libtool version to 2.1.0
- . dumb font rendering works
- . slot user attributes are now signed rather than unsigned
- . add support for long class maps
- . Rename perl library to avoid nameclash on Windows
- . Various robustness fixes
- . Moved internal .h files into src/inc
- . Parallelise fuzztest
- . General build improvements, particularly on Windows
-
-1.0.3
- . Fix UTF16 surrogate support
- . script and lang tags may be space padded or null padded
- . Remove need for WORDS_BIGENDIAN, do it all automatically
- . Remove all #include <new>. Use CLASS_NEW_DELETE instead.
- . Fix comparerenderer to work with current hbng
- . Add valgrind to fuzztest to ensure good memory use at all times
- . Fix new fuzztest exposed bugs.
- . Fix bugs exposed by Mozilla security review
- . Add continuous integration build on Windows support
-
-1.0.2
- . Fix Windows build
- . Comparerenderer uses hbng enforcing ot rendering
- . Add Bidi .hasChar support and refactor mirroring code
- . Make cmake default Release rather than debug
- . Don't compile in a boat load of TtfUtil that isn't used, saving 15% of binary
- . Chase the FSF around its latest office moves
- . WORDS_BIGENDIAN is set at the top so tests now pass on ppc, etc.
- . More words in the manual
-
-1.0.1
- . Release is the default build in cmake now.
- . Refactor cmake build to not rebuild things so much.
- . Include a missing file
- . Remove -nostdlibs, making gcc happy everywhere
- . Update comparerenderer to latest hbng interface
- . Add changelog
-
-1.0.0
- . First major release of perfect code!
-
diff --git a/thirdparty/graphite/src/Pass.cpp b/thirdparty/graphite/src/Pass.cpp
index db31c22d46..47ae2064f7 100644
--- a/thirdparty/graphite/src/Pass.cpp
+++ b/thirdparty/graphite/src/Pass.cpp
@@ -1056,12 +1056,17 @@ float Pass::resolveKern(Segment *seg, Slot *slotFix, GR_MAYBE_UNUSED Slot *start
ymin = min(by + bbb.bl.y, ymin);
for (nbor = slotFix->next(); nbor; nbor = nbor->next())
{
- if (nbor->isChildOf(base))
- continue;
if (!gc.check(nbor->gid()))
return 0.;
const Rect &bb = seg->theGlyphBBoxTemporary(nbor->gid());
SlotCollision *cNbor = seg->collisionInfo(nbor);
+ const float nby = nbor->origin().y + cNbor->shift().y;
+ if (nbor->isChildOf(base))
+ {
+ ymax = max(nby + bb.tr.y, ymax);
+ ymin = min(nby + bb.bl.y, ymin);
+ continue;
+ }
if ((bb.bl.y == 0.f && bb.tr.y == 0.f) || (cNbor->flags() & SlotCollision::COLL_ISSPACE))
{
if (m_kernColls == InWord)
diff --git a/thirdparty/libogg/framing.c b/thirdparty/libogg/framing.c
index 83601199ad..724d116d7f 100644
--- a/thirdparty/libogg/framing.c
+++ b/thirdparty/libogg/framing.c
@@ -597,9 +597,14 @@ char *ogg_sync_buffer(ogg_sync_state *oy, long size){
if(size>oy->storage-oy->fill){
/* We need to extend the internal buffer */
- long newsize=size+oy->fill+4096; /* an extra page to be nice */
+ long newsize;
void *ret;
+ if(size>INT_MAX-4096-oy->fill){
+ ogg_sync_clear(oy);
+ return NULL;
+ }
+ newsize=size+oy->fill+4096; /* an extra page to be nice */
if(oy->data)
ret=_ogg_realloc(oy->data,newsize);
else
@@ -1564,7 +1569,7 @@ void test_pack(const int *pl, const int **headers, int byteskip,
byteskipcount=byteskip;
}
- ogg_sync_wrote(&oy,next-buf);
+ ogg_sync_wrote(&oy,(long)(next-buf));
while(1){
int ret=ogg_sync_pageout(&oy,&og_de);
diff --git a/thirdparty/libogg/ogg/config_types.h b/thirdparty/libogg/ogg/config_types.h
index 4dc8393fdc..1a87df6423 100644
--- a/thirdparty/libogg/ogg/config_types.h
+++ b/thirdparty/libogg/ogg/config_types.h
@@ -1,7 +1,20 @@
#ifndef __CONFIG_TYPES_H__
#define __CONFIG_TYPES_H__
-#include <stdint.h>
+/* these are filled in by configure or cmake*/
+#define INCLUDE_INTTYPES_H 1
+#define INCLUDE_STDINT_H 1
+#define INCLUDE_SYS_TYPES_H 1
+
+#if INCLUDE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#if INCLUDE_STDINT_H
+# include <stdint.h>
+#endif
+#if INCLUDE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
typedef int16_t ogg_int16_t;
typedef uint16_t ogg_uint16_t;
diff --git a/thirdparty/libvorbis/COPYING b/thirdparty/libvorbis/COPYING
index 153b926a15..fb456a87bd 100644
--- a/thirdparty/libvorbis/COPYING
+++ b/thirdparty/libvorbis/COPYING
@@ -1,4 +1,4 @@
-Copyright (c) 2002-2018 Xiph.org Foundation
+Copyright (c) 2002-2020 Xiph.org Foundation
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
diff --git a/thirdparty/libvorbis/analysis.c b/thirdparty/libvorbis/analysis.c
index 0e11a167be..14919737eb 100644
--- a/thirdparty/libvorbis/analysis.c
+++ b/thirdparty/libvorbis/analysis.c
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/backends.h b/thirdparty/libvorbis/backends.h
index 22809d46d5..670b0b902e 100644
--- a/thirdparty/libvorbis/backends.h
+++ b/thirdparty/libvorbis/backends.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/barkmel.c b/thirdparty/libvorbis/barkmel.c
index 4b19935f30..f833c30211 100644
--- a/thirdparty/libvorbis/barkmel.c
+++ b/thirdparty/libvorbis/barkmel.c
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/bitrate.c b/thirdparty/libvorbis/bitrate.c
index 96055140f7..132553cbee 100644
--- a/thirdparty/libvorbis/bitrate.c
+++ b/thirdparty/libvorbis/bitrate.c
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/bitrate.h b/thirdparty/libvorbis/bitrate.h
index 655a68cc09..48fa150596 100644
--- a/thirdparty/libvorbis/bitrate.h
+++ b/thirdparty/libvorbis/bitrate.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/block.c b/thirdparty/libvorbis/block.c
index db245b3e69..6a50da0843 100644
--- a/thirdparty/libvorbis/block.c
+++ b/thirdparty/libvorbis/block.c
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/books/coupled/res_books_51.h b/thirdparty/libvorbis/books/coupled/res_books_51.h
index 47df4b221b..eb569c6f04 100644
--- a/thirdparty/libvorbis/books/coupled/res_books_51.h
+++ b/thirdparty/libvorbis/books/coupled/res_books_51.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
*
diff --git a/thirdparty/libvorbis/books/coupled/res_books_stereo.h b/thirdparty/libvorbis/books/coupled/res_books_stereo.h
index 61d934046d..7b53cb972b 100644
--- a/thirdparty/libvorbis/books/coupled/res_books_stereo.h
+++ b/thirdparty/libvorbis/books/coupled/res_books_stereo.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/books/floor/floor_books.h b/thirdparty/libvorbis/books/floor/floor_books.h
index 67d5f31a3b..d26664f766 100644
--- a/thirdparty/libvorbis/books/floor/floor_books.h
+++ b/thirdparty/libvorbis/books/floor/floor_books.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/books/uncoupled/res_books_uncoupled.h b/thirdparty/libvorbis/books/uncoupled/res_books_uncoupled.h
index 3d658ec470..107e22f9e3 100644
--- a/thirdparty/libvorbis/books/uncoupled/res_books_uncoupled.h
+++ b/thirdparty/libvorbis/books/uncoupled/res_books_uncoupled.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/codebook.c b/thirdparty/libvorbis/codebook.c
index 78672e222d..7a0c206783 100644
--- a/thirdparty/libvorbis/codebook.c
+++ b/thirdparty/libvorbis/codebook.c
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/codebook.h b/thirdparty/libvorbis/codebook.h
index 08440c6962..7d4e2aae4f 100644
--- a/thirdparty/libvorbis/codebook.h
+++ b/thirdparty/libvorbis/codebook.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/codec_internal.h b/thirdparty/libvorbis/codec_internal.h
index e522be18da..2ecf5e5c73 100644
--- a/thirdparty/libvorbis/codec_internal.h
+++ b/thirdparty/libvorbis/codec_internal.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/envelope.c b/thirdparty/libvorbis/envelope.c
index da75237542..22d39aa6e0 100644
--- a/thirdparty/libvorbis/envelope.c
+++ b/thirdparty/libvorbis/envelope.c
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/envelope.h b/thirdparty/libvorbis/envelope.h
index f466efde8a..2ef60a82ca 100644
--- a/thirdparty/libvorbis/envelope.h
+++ b/thirdparty/libvorbis/envelope.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/floor0.c b/thirdparty/libvorbis/floor0.c
index 443c0e5a96..f4a6d4d559 100644
--- a/thirdparty/libvorbis/floor0.c
+++ b/thirdparty/libvorbis/floor0.c
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/floor1.c b/thirdparty/libvorbis/floor1.c
index 673e954c53..c4fe3ea7e7 100644
--- a/thirdparty/libvorbis/floor1.c
+++ b/thirdparty/libvorbis/floor1.c
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/highlevel.h b/thirdparty/libvorbis/highlevel.h
index 337b75bfa4..7690e3ebfb 100644
--- a/thirdparty/libvorbis/highlevel.h
+++ b/thirdparty/libvorbis/highlevel.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/info.c b/thirdparty/libvorbis/info.c
index 3fbb7c757a..f2e39e387e 100644
--- a/thirdparty/libvorbis/info.c
+++ b/thirdparty/libvorbis/info.c
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
@@ -19,7 +19,6 @@
#include <stdlib.h>
#include <string.h>
-#include <ctype.h>
#include <ogg/ogg.h>
#include "vorbis/codec.h"
#include "codec_internal.h"
@@ -30,8 +29,8 @@
#include "misc.h"
#include "os.h"
-#define GENERAL_VENDOR_STRING "Xiph.Org libVorbis 1.3.6"
-#define ENCODE_VENDOR_STRING "Xiph.Org libVorbis I 20180316 (Now 100% fewer shells)"
+#define GENERAL_VENDOR_STRING "Xiph.Org libVorbis 1.3.7"
+#define ENCODE_VENDOR_STRING "Xiph.Org libVorbis I 20200704 (Reducing Environment)"
/* helpers */
static void _v_writestring(oggpack_buffer *o,const char *s, int bytes){
@@ -47,6 +46,10 @@ static void _v_readstring(oggpack_buffer *o,char *buf,int bytes){
}
}
+static int _v_toupper(int c) {
+ return (c >= 'a' && c <= 'z') ? (c & ~('a' - 'A')) : c;
+}
+
void vorbis_comment_init(vorbis_comment *vc){
memset(vc,0,sizeof(*vc));
}
@@ -78,7 +81,7 @@ void vorbis_comment_add_tag(vorbis_comment *vc, const char *tag, const char *con
static int tagcompare(const char *s1, const char *s2, int n){
int c=0;
while(c < n){
- if(toupper(s1[c]) != toupper(s2[c]))
+ if(_v_toupper(s1[c]) != _v_toupper(s2[c]))
return !0;
c++;
}
@@ -203,6 +206,7 @@ void vorbis_info_clear(vorbis_info *vi){
static int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb){
codec_setup_info *ci=vi->codec_setup;
+ int bs;
if(!ci)return(OV_EFAULT);
vi->version=oggpack_read(opb,32);
@@ -215,8 +219,12 @@ static int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb){
vi->bitrate_nominal=(ogg_int32_t)oggpack_read(opb,32);
vi->bitrate_lower=(ogg_int32_t)oggpack_read(opb,32);
- ci->blocksizes[0]=1<<oggpack_read(opb,4);
- ci->blocksizes[1]=1<<oggpack_read(opb,4);
+ bs = oggpack_read(opb,4);
+ if(bs<0)goto err_out;
+ ci->blocksizes[0]=1<<bs;
+ bs = oggpack_read(opb,4);
+ if(bs<0)goto err_out;
+ ci->blocksizes[1]=1<<bs;
if(vi->rate<1)goto err_out;
if(vi->channels<1)goto err_out;
diff --git a/thirdparty/libvorbis/lookup.c b/thirdparty/libvorbis/lookup.c
index 1cc1f88ee9..7cd01a44d3 100644
--- a/thirdparty/libvorbis/lookup.c
+++ b/thirdparty/libvorbis/lookup.c
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/lookup.h b/thirdparty/libvorbis/lookup.h
index 4bc0f3a206..ec05014f44 100644
--- a/thirdparty/libvorbis/lookup.h
+++ b/thirdparty/libvorbis/lookup.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/lookup_data.h b/thirdparty/libvorbis/lookup_data.h
index 5de3cfdc7e..7935715a70 100644
--- a/thirdparty/libvorbis/lookup_data.h
+++ b/thirdparty/libvorbis/lookup_data.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/lpc.c b/thirdparty/libvorbis/lpc.c
index 798f4cf076..877da47f8e 100644
--- a/thirdparty/libvorbis/lpc.c
+++ b/thirdparty/libvorbis/lpc.c
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/lpc.h b/thirdparty/libvorbis/lpc.h
index 9cc79451b6..4f59e6d32d 100644
--- a/thirdparty/libvorbis/lpc.h
+++ b/thirdparty/libvorbis/lpc.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/lsp.c b/thirdparty/libvorbis/lsp.c
index 8588054515..8afa305f50 100644
--- a/thirdparty/libvorbis/lsp.c
+++ b/thirdparty/libvorbis/lsp.c
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
@@ -15,9 +15,10 @@
The LSP generation code is taken (with minimal modification and a
few bugfixes) from "On the Computation of the LSP Frequencies" by
Joseph Rothweiler (see http://www.rothweiler.us for contact info).
+
The paper is available at:
- http://www.myown1.com/joe/lsf
+ https://web.archive.org/web/20110810174000/http://home.myfairpoint.net/vzenxj75/myown1/joe/lsf/index.html
********************************************************************/
diff --git a/thirdparty/libvorbis/lsp.h b/thirdparty/libvorbis/lsp.h
index 8a8d10e978..68b38daf16 100644
--- a/thirdparty/libvorbis/lsp.h
+++ b/thirdparty/libvorbis/lsp.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/mapping0.c b/thirdparty/libvorbis/mapping0.c
index ccb4493d4c..efa0fbcd93 100644
--- a/thirdparty/libvorbis/mapping0.c
+++ b/thirdparty/libvorbis/mapping0.c
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/masking.h b/thirdparty/libvorbis/masking.h
index 955e18c719..7a196a37eb 100644
--- a/thirdparty/libvorbis/masking.h
+++ b/thirdparty/libvorbis/masking.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/mdct.c b/thirdparty/libvorbis/mdct.c
index f3f1ed805b..2a0ff8d01b 100644
--- a/thirdparty/libvorbis/mdct.c
+++ b/thirdparty/libvorbis/mdct.c
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/mdct.h b/thirdparty/libvorbis/mdct.h
index 3b8c9ba4a2..ceaea617a3 100644
--- a/thirdparty/libvorbis/mdct.h
+++ b/thirdparty/libvorbis/mdct.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/misc.h b/thirdparty/libvorbis/misc.h
index 13788445a3..eac5160e88 100644
--- a/thirdparty/libvorbis/misc.h
+++ b/thirdparty/libvorbis/misc.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/modes/floor_all.h b/thirdparty/libvorbis/modes/floor_all.h
index 20928aac87..2e3d4a5012 100644
--- a/thirdparty/libvorbis/modes/floor_all.h
+++ b/thirdparty/libvorbis/modes/floor_all.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/modes/psych_11.h b/thirdparty/libvorbis/modes/psych_11.h
index cc5eea2402..9d8ed357ee 100644
--- a/thirdparty/libvorbis/modes/psych_11.h
+++ b/thirdparty/libvorbis/modes/psych_11.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/modes/psych_16.h b/thirdparty/libvorbis/modes/psych_16.h
index 477cb4d90f..49cbf7c4b2 100644
--- a/thirdparty/libvorbis/modes/psych_16.h
+++ b/thirdparty/libvorbis/modes/psych_16.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/modes/psych_44.h b/thirdparty/libvorbis/modes/psych_44.h
index 6c9eaa4e5f..d15509b71d 100644
--- a/thirdparty/libvorbis/modes/psych_44.h
+++ b/thirdparty/libvorbis/modes/psych_44.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/modes/psych_8.h b/thirdparty/libvorbis/modes/psych_8.h
index 277db8436c..a19817f760 100644
--- a/thirdparty/libvorbis/modes/psych_8.h
+++ b/thirdparty/libvorbis/modes/psych_8.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/modes/residue_16.h b/thirdparty/libvorbis/modes/residue_16.h
index 3e05471cec..15e161c862 100644
--- a/thirdparty/libvorbis/modes/residue_16.h
+++ b/thirdparty/libvorbis/modes/residue_16.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/modes/residue_44.h b/thirdparty/libvorbis/modes/residue_44.h
index e89bc0e486..3f982695a7 100644
--- a/thirdparty/libvorbis/modes/residue_44.h
+++ b/thirdparty/libvorbis/modes/residue_44.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/modes/residue_44p51.h b/thirdparty/libvorbis/modes/residue_44p51.h
index 7f33e250e2..8ac5f65e62 100644
--- a/thirdparty/libvorbis/modes/residue_44p51.h
+++ b/thirdparty/libvorbis/modes/residue_44p51.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/modes/residue_44u.h b/thirdparty/libvorbis/modes/residue_44u.h
index e55ac12548..2f3595e49f 100644
--- a/thirdparty/libvorbis/modes/residue_44u.h
+++ b/thirdparty/libvorbis/modes/residue_44u.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/modes/residue_8.h b/thirdparty/libvorbis/modes/residue_8.h
index ae123a276a..b836f79c84 100644
--- a/thirdparty/libvorbis/modes/residue_8.h
+++ b/thirdparty/libvorbis/modes/residue_8.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/modes/setup_11.h b/thirdparty/libvorbis/modes/setup_11.h
index 0cbcaafcb2..5ade5dd169 100644
--- a/thirdparty/libvorbis/modes/setup_11.h
+++ b/thirdparty/libvorbis/modes/setup_11.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/modes/setup_16.h b/thirdparty/libvorbis/modes/setup_16.h
index d59ad70d2e..8b2daafa3f 100644
--- a/thirdparty/libvorbis/modes/setup_16.h
+++ b/thirdparty/libvorbis/modes/setup_16.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/modes/setup_22.h b/thirdparty/libvorbis/modes/setup_22.h
index bc38af9630..eef5a4e7da 100644
--- a/thirdparty/libvorbis/modes/setup_22.h
+++ b/thirdparty/libvorbis/modes/setup_22.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/modes/setup_32.h b/thirdparty/libvorbis/modes/setup_32.h
index f66a0bcd00..f87cb767d0 100644
--- a/thirdparty/libvorbis/modes/setup_32.h
+++ b/thirdparty/libvorbis/modes/setup_32.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/modes/setup_44.h b/thirdparty/libvorbis/modes/setup_44.h
index a189b5fb95..12d592808e 100644
--- a/thirdparty/libvorbis/modes/setup_44.h
+++ b/thirdparty/libvorbis/modes/setup_44.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/modes/setup_44p51.h b/thirdparty/libvorbis/modes/setup_44p51.h
index 3bde7b340c..4d49173ffb 100644
--- a/thirdparty/libvorbis/modes/setup_44p51.h
+++ b/thirdparty/libvorbis/modes/setup_44p51.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/modes/setup_44u.h b/thirdparty/libvorbis/modes/setup_44u.h
index 7ae3af6b2a..2dd8bf701f 100644
--- a/thirdparty/libvorbis/modes/setup_44u.h
+++ b/thirdparty/libvorbis/modes/setup_44u.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/modes/setup_8.h b/thirdparty/libvorbis/modes/setup_8.h
index 7502556879..16b02e01b7 100644
--- a/thirdparty/libvorbis/modes/setup_8.h
+++ b/thirdparty/libvorbis/modes/setup_8.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/modes/setup_X.h b/thirdparty/libvorbis/modes/setup_X.h
index 2229a5ef2f..27807c10b4 100644
--- a/thirdparty/libvorbis/modes/setup_X.h
+++ b/thirdparty/libvorbis/modes/setup_X.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/os.h b/thirdparty/libvorbis/os.h
index 416a401dd1..9ded7358d4 100644
--- a/thirdparty/libvorbis/os.h
+++ b/thirdparty/libvorbis/os.h
@@ -8,7 +8,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
@@ -60,7 +60,7 @@ void *_alloca(size_t size);
# define FAST_HYPOT hypot
#endif
-#endif
+#endif /* _V_IFDEFJAIL_H_ */
#ifdef HAVE_ALLOCA_H
# include <alloca.h>
@@ -80,7 +80,7 @@ void *_alloca(size_t size);
/* Special i386 GCC implementation */
-#if defined(__i386__) && defined(__GNUC__) && !defined(__BEOS__)
+#if defined(__i386__) && defined(__GNUC__) && !defined(__BEOS__) && !defined(__SSE2_MATH__)
# define VORBIS_FPU_CONTROL
/* both GCC and MSVC are kinda stupid about rounding/casting to int.
Because of encapsulation constraints (GCC can't see inside the asm
@@ -119,8 +119,7 @@ static inline int vorbis_ftoi(double f){ /* yes, double! Otherwise,
/* MSVC inline assembly. 32 bit only; inline ASM isn't implemented in the
* 64 bit compiler and doesn't work on arm. */
-#if defined(_MSC_VER) && !defined(_WIN64) && \
- !defined(_WIN32_WCE) && !defined(_M_ARM)
+#if defined(_MSC_VER) && defined(_M_IX86) && !defined(_WIN32_WCE)
# define VORBIS_FPU_CONTROL
typedef ogg_int16_t vorbis_fpu_control;
@@ -147,7 +146,7 @@ static __inline void vorbis_fpu_restore(vorbis_fpu_control fpu){
/* Optimized code path for x86_64 builds. Uses SSE2 intrinsics. This can be
done safely because all x86_64 CPUs supports SSE2. */
-#if (defined(_MSC_VER) && defined(_WIN64)) || (defined(__GNUC__) && defined (__x86_64__))
+#if (defined(_MSC_VER) && defined(_M_X64)) || (defined(__GNUC__) && defined (__SSE2_MATH__))
# define VORBIS_FPU_CONTROL
typedef ogg_int16_t vorbis_fpu_control;
@@ -174,7 +173,7 @@ static __inline void vorbis_fpu_restore(vorbis_fpu_control fpu){
typedef int vorbis_fpu_control;
-static int vorbis_ftoi(double f){
+STIN int vorbis_ftoi(double f){
/* Note: MSVC and GCC (at least on some systems) round towards zero, thus,
the floor() call is required to ensure correct roudning of
negative numbers */
diff --git a/thirdparty/libvorbis/psy.c b/thirdparty/libvorbis/psy.c
index 422c6f1e41..036b094aa7 100644
--- a/thirdparty/libvorbis/psy.c
+++ b/thirdparty/libvorbis/psy.c
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
@@ -599,11 +599,12 @@ static void bark_noise_hybridmp(int n,const long *b,
XY[i] = tXY;
}
- for (i = 0, x = 0.f;; i++, x += 1.f) {
+ for (i = 0, x = 0.f; i < n; i++, x += 1.f) {
lo = b[i] >> 16;
- if( lo>=0 ) break;
hi = b[i] & 0xffff;
+ if( lo>=0 || -lo>=n ) break;
+ if( hi>=n ) break;
tN = N[hi] + N[-lo];
tX = X[hi] - X[-lo];
@@ -615,17 +616,17 @@ static void bark_noise_hybridmp(int n,const long *b,
B = tN * tXY - tX * tY;
D = tN * tXX - tX * tX;
R = (A + x * B) / D;
- if (R < 0.f)
- R = 0.f;
+ if (R < 0.f) R = 0.f;
noise[i] = R - offset;
}
- for ( ;; i++, x += 1.f) {
+ for ( ; i < n; i++, x += 1.f) {
lo = b[i] >> 16;
hi = b[i] & 0xffff;
- if(hi>=n)break;
+ if( lo<0 || lo>=n ) break;
+ if( hi>=n ) break;
tN = N[hi] - N[lo];
tX = X[hi] - X[lo];
@@ -641,6 +642,7 @@ static void bark_noise_hybridmp(int n,const long *b,
noise[i] = R - offset;
}
+
for ( ; i < n; i++, x += 1.f) {
R = (A + x * B) / D;
@@ -651,10 +653,11 @@ static void bark_noise_hybridmp(int n,const long *b,
if (fixed <= 0) return;
- for (i = 0, x = 0.f;; i++, x += 1.f) {
+ for (i = 0, x = 0.f; i < n; i++, x += 1.f) {
hi = i + fixed / 2;
lo = hi - fixed;
- if(lo>=0)break;
+ if ( hi>=n ) break;
+ if ( lo>=0 ) break;
tN = N[hi] + N[-lo];
tX = X[hi] - X[-lo];
@@ -670,11 +673,12 @@ static void bark_noise_hybridmp(int n,const long *b,
if (R - offset < noise[i]) noise[i] = R - offset;
}
- for ( ;; i++, x += 1.f) {
+ for ( ; i < n; i++, x += 1.f) {
hi = i + fixed / 2;
lo = hi - fixed;
- if(hi>=n)break;
+ if ( hi>=n ) break;
+ if ( lo<0 ) break;
tN = N[hi] - N[lo];
tX = X[hi] - X[lo];
diff --git a/thirdparty/libvorbis/psy.h b/thirdparty/libvorbis/psy.h
index ab2534db3a..d9a04e8b74 100644
--- a/thirdparty/libvorbis/psy.h
+++ b/thirdparty/libvorbis/psy.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/psytune.c b/thirdparty/libvorbis/psytune.c
index 6952136c6b..67223e5118 100644
--- a/thirdparty/libvorbis/psytune.c
+++ b/thirdparty/libvorbis/psytune.c
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/registry.c b/thirdparty/libvorbis/registry.c
index 74f7ef0396..db0f67b2e2 100644
--- a/thirdparty/libvorbis/registry.c
+++ b/thirdparty/libvorbis/registry.c
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/registry.h b/thirdparty/libvorbis/registry.h
index 599d959942..b823aa6091 100644
--- a/thirdparty/libvorbis/registry.h
+++ b/thirdparty/libvorbis/registry.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/res0.c b/thirdparty/libvorbis/res0.c
index 6d623d730f..c931aded38 100644
--- a/thirdparty/libvorbis/res0.c
+++ b/thirdparty/libvorbis/res0.c
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
@@ -30,9 +30,6 @@
#include "misc.h"
#include "os.h"
-//#define TRAIN_RES 1
-//#define TRAIN_RESAUX 1
-
#if defined(TRAIN_RES) || defined (TRAIN_RESAUX)
#include <stdio.h>
#endif
diff --git a/thirdparty/libvorbis/scales.h b/thirdparty/libvorbis/scales.h
index 18bc4e7518..3c2ae48d9e 100644
--- a/thirdparty/libvorbis/scales.h
+++ b/thirdparty/libvorbis/scales.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/sharedbook.c b/thirdparty/libvorbis/sharedbook.c
index 4545d4f459..62a9a00afb 100644
--- a/thirdparty/libvorbis/sharedbook.c
+++ b/thirdparty/libvorbis/sharedbook.c
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
@@ -50,7 +50,7 @@ long _float32_pack(float val){
sign=0x80000000;
val= -val;
}
- exp= floor(log(val)/log(2.f)+.001); //+epsilon
+ exp= floor(log(val)/log(2.f)+.001); /* +epsilon */
mant=rint(ldexp(val,(VQ_FMAN-1)-exp));
exp=(exp+VQ_FEXP_BIAS)<<VQ_FMAN;
@@ -62,7 +62,15 @@ float _float32_unpack(long val){
int sign=val&0x80000000;
long exp =(val&0x7fe00000L)>>VQ_FMAN;
if(sign)mant= -mant;
- return(ldexp(mant,exp-(VQ_FMAN-1)-VQ_FEXP_BIAS));
+ exp=exp-(VQ_FMAN-1)-VQ_FEXP_BIAS;
+ /* clamp excessive exponent values */
+ if (exp>63){
+ exp=63;
+ }
+ if (exp<-63){
+ exp=-63;
+ }
+ return(ldexp(mant,exp));
}
/* given a list of word lengths, generate a list of codewords. Works
@@ -294,7 +302,7 @@ int vorbis_book_init_encode(codebook *c,const static_codebook *s){
c->used_entries=s->entries;
c->dim=s->dim;
c->codelist=_make_words(s->lengthlist,s->entries,0);
- //c->valuelist=_book_unquantize(s,s->entries,NULL);
+ /* c->valuelist=_book_unquantize(s,s->entries,NULL); */
c->quantvals=_book_maptype1_quantvals(s);
c->minval=(int)rint(_float32_unpack(s->q_min));
c->delta=(int)rint(_float32_unpack(s->q_delta));
@@ -573,6 +581,7 @@ void run_test(static_codebook *b,float *comp){
exit(1);
}
}
+ free(out);
}
int main(){
diff --git a/thirdparty/libvorbis/smallft.c b/thirdparty/libvorbis/smallft.c
index 6d528af423..4ffabab4bb 100644
--- a/thirdparty/libvorbis/smallft.c
+++ b/thirdparty/libvorbis/smallft.c
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/smallft.h b/thirdparty/libvorbis/smallft.h
index 9e867c67d2..02fe8f9cd4 100644
--- a/thirdparty/libvorbis/smallft.h
+++ b/thirdparty/libvorbis/smallft.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/synthesis.c b/thirdparty/libvorbis/synthesis.c
index 5f6092c3d3..3e2d681270 100644
--- a/thirdparty/libvorbis/synthesis.c
+++ b/thirdparty/libvorbis/synthesis.c
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/vorbis/codec.h b/thirdparty/libvorbis/vorbis/codec.h
index 42aa29138e..f8a912bc26 100644
--- a/thirdparty/libvorbis/vorbis/codec.h
+++ b/thirdparty/libvorbis/vorbis/codec.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
********************************************************************
diff --git a/thirdparty/libvorbis/vorbis/vorbisenc.h b/thirdparty/libvorbis/vorbis/vorbisenc.h
index 55f3b4a667..085b15e669 100644
--- a/thirdparty/libvorbis/vorbis/vorbisenc.h
+++ b/thirdparty/libvorbis/vorbis/vorbisenc.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/vorbis/vorbisfile.h b/thirdparty/libvorbis/vorbis/vorbisfile.h
index 56626119bb..3d65393f52 100644
--- a/thirdparty/libvorbis/vorbis/vorbisfile.h
+++ b/thirdparty/libvorbis/vorbis/vorbisfile.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/vorbisenc.c b/thirdparty/libvorbis/vorbisenc.c
index 4a4607cb41..cf3806a6e1 100644
--- a/thirdparty/libvorbis/vorbisenc.c
+++ b/thirdparty/libvorbis/vorbisenc.c
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
@@ -684,6 +684,7 @@ int vorbis_encode_setup_init(vorbis_info *vi){
highlevel_encode_setup *hi=&ci->hi;
if(ci==NULL)return(OV_EINVAL);
+ if(vi->channels<1||vi->channels>255)return(OV_EINVAL);
if(!hi->impulse_block_p)i0=1;
/* too low/high an ATH floater is nonsensical, but doesn't break anything */
@@ -1210,7 +1211,7 @@ int vorbis_encode_ctl(vorbis_info *vi,int number,void *arg){
hi->req,
hi->managed,
&new_base);
- if(!hi->setup)return OV_EIMPL;
+ if(!new_template)return OV_EIMPL;
hi->setup=new_template;
hi->base_setting=new_base;
vorbis_encode_setup_setting(vi,vi->channels,vi->rate);
diff --git a/thirdparty/libvorbis/vorbisfile.c b/thirdparty/libvorbis/vorbisfile.c
index b570c3c5f6..9219c2f2dc 100644
--- a/thirdparty/libvorbis/vorbisfile.c
+++ b/thirdparty/libvorbis/vorbisfile.c
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
@@ -264,6 +264,10 @@ static ogg_int64_t _get_prev_page_serial(OggVorbis_File *vf, ogg_int64_t begin,
}
}
}
+ /*We started from the beginning of the stream and found nothing.
+ This should be impossible unless the contents of the stream changed out
+ from under us after we read from it.*/
+ if(!begin&&vf->offset<0)return OV_EBADLINK;
}
/* we're not interested in the page... just the serialno and granpos. */
@@ -1230,7 +1234,6 @@ double ov_time_total(OggVorbis_File *vf,int i){
int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){
ogg_stream_state work_os;
- int ret;
if(vf->ready_state<OPENED)return(OV_EINVAL);
if(!vf->seekable)
@@ -1253,8 +1256,12 @@ int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){
vf->current_serialno); /* must set serialno */
vorbis_synthesis_restart(&vf->vd);
- ret=_seek_helper(vf,pos);
- if(ret)goto seek_error;
+ if(_seek_helper(vf,pos)) {
+ /* dump the machine so we're in a known state */
+ vf->pcm_offset=-1;
+ _decode_clear(vf);
+ return OV_EBADLINK;
+ }
/* we need to make sure the pcm_offset is set, but we don't want to
advance the raw cursor past good packets just to get to the first
@@ -1388,13 +1395,6 @@ int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){
vf->bittrack=0.f;
vf->samptrack=0.f;
return(0);
-
- seek_error:
- /* dump the machine so we're in a known state */
- vf->pcm_offset=-1;
- ogg_stream_clear(&work_os);
- _decode_clear(vf);
- return OV_EBADLINK;
}
/* Page granularity seek (faster than sample granularity because we
@@ -1964,6 +1964,7 @@ long ov_read_filter(OggVorbis_File *vf,char *buffer,int length,
long samples;
if(vf->ready_state<OPENED)return(OV_EINVAL);
+ if(word<=0)return(OV_EINVAL);
while(1){
if(vf->ready_state==INITSET){
@@ -1989,6 +1990,8 @@ long ov_read_filter(OggVorbis_File *vf,char *buffer,int length,
long channels=ov_info(vf,-1)->channels;
long bytespersample=word * channels;
vorbis_fpu_control fpu;
+
+ if(channels<1||channels>255)return(OV_EINVAL);
if(samples>length/bytespersample)samples=length/bytespersample;
if(samples <= 0)
diff --git a/thirdparty/libvorbis/window.c b/thirdparty/libvorbis/window.c
index b3b7ce0163..2151b278d1 100644
--- a/thirdparty/libvorbis/window.c
+++ b/thirdparty/libvorbis/window.c
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libvorbis/window.h b/thirdparty/libvorbis/window.h
index 6ac260749e..33d83f85f9 100644
--- a/thirdparty/libvorbis/window.h
+++ b/thirdparty/libvorbis/window.h
@@ -6,7 +6,7 @@
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
diff --git a/thirdparty/libwebp/AUTHORS b/thirdparty/libwebp/AUTHORS
index 0d70b7fb2a..30abde0326 100644
--- a/thirdparty/libwebp/AUTHORS
+++ b/thirdparty/libwebp/AUTHORS
@@ -1,9 +1,15 @@
Contributors:
+- Aidan O'Loan (aidanol at gmail dot com)
- Alan Browning (browning at google dot com)
- Charles Munger (clm at google dot com)
+- Cheng Yi (cyi at google dot com)
- Christian Duvivier (cduvivier at google dot com)
+- Christopher Degawa (ccom at randomderp dot com)
+- Clement Courbet (courbet at google dot com)
- Djordje Pesut (djordje dot pesut at imgtec dot com)
- Hui Su (huisu at google dot com)
+- Ilya Kurdyukov (jpegqs at gmail dot com)
+- Ingvar Stepanyan (rreverser at google dot com)
- James Zern (jzern at google dot com)
- Jan Engelhardt (jengelh at medozas dot de)
- Jehan (jehan at girinstud dot io)
@@ -20,6 +26,7 @@ Contributors:
- Mislav Bradac (mislavm at google dot com)
- Nico Weber (thakis at chromium dot org)
- Noel Chromium (noel at chromium dot org)
+- Oliver Wolff (oliver dot wolff at qt dot io)
- Owen Rodley (orodley at google dot com)
- Parag Salasakar (img dot mips1 at gmail dot com)
- Pascal Massimino (pascal dot massimino at gmail dot com)
@@ -38,5 +45,7 @@ Contributors:
- Vikas Arora (vikasa at google dot com)
- Vincent Rabaud (vrabaud at google dot com)
- Vlad Tsyrklevich (vtsyrklevich at chromium dot org)
+- Wan-Teh Chang (wtc at google dot com)
- Yang Zhang (yang dot zhang at arm dot com)
- Yannis Guyon (yguyon at google dot com)
+- Zhi An Ng (zhin at chromium dot org)
diff --git a/thirdparty/libwebp/src/dec/alpha_dec.c b/thirdparty/libwebp/src/dec/alpha_dec.c
index bce735bfc2..0b93a30b32 100644
--- a/thirdparty/libwebp/src/dec/alpha_dec.c
+++ b/thirdparty/libwebp/src/dec/alpha_dec.c
@@ -183,7 +183,7 @@ const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
assert(dec != NULL && io != NULL);
if (row < 0 || num_rows <= 0 || row + num_rows > height) {
- return NULL; // sanity check.
+ return NULL;
}
if (!dec->is_alpha_decoded_) {
diff --git a/thirdparty/libwebp/src/dec/buffer_dec.c b/thirdparty/libwebp/src/dec/buffer_dec.c
index 3cd94eb4d9..4786cf0ddb 100644
--- a/thirdparty/libwebp/src/dec/buffer_dec.c
+++ b/thirdparty/libwebp/src/dec/buffer_dec.c
@@ -102,7 +102,7 @@ static VP8StatusCode AllocateBuffer(WebPDecBuffer* const buffer) {
int stride;
uint64_t size;
- if ((uint64_t)w * kModeBpp[mode] >= (1ull << 32)) {
+ if ((uint64_t)w * kModeBpp[mode] >= (1ull << 31)) {
return VP8_STATUS_INVALID_PARAM;
}
stride = w * kModeBpp[mode];
@@ -117,7 +117,6 @@ static VP8StatusCode AllocateBuffer(WebPDecBuffer* const buffer) {
}
total_size = size + 2 * uv_size + a_size;
- // Security/sanity checks
output = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*output));
if (output == NULL) {
return VP8_STATUS_OUT_OF_MEMORY;
@@ -156,11 +155,11 @@ VP8StatusCode WebPFlipBuffer(WebPDecBuffer* const buffer) {
}
if (WebPIsRGBMode(buffer->colorspace)) {
WebPRGBABuffer* const buf = &buffer->u.RGBA;
- buf->rgba += (buffer->height - 1) * buf->stride;
+ buf->rgba += (int64_t)(buffer->height - 1) * buf->stride;
buf->stride = -buf->stride;
} else {
WebPYUVABuffer* const buf = &buffer->u.YUVA;
- const int H = buffer->height;
+ const int64_t H = buffer->height;
buf->y += (H - 1) * buf->y_stride;
buf->y_stride = -buf->y_stride;
buf->u += ((H - 1) >> 1) * buf->u_stride;
@@ -188,8 +187,7 @@ VP8StatusCode WebPAllocateDecBuffer(int width, int height,
const int ch = options->crop_height;
const int x = options->crop_left & ~1;
const int y = options->crop_top & ~1;
- if (x < 0 || y < 0 || cw <= 0 || ch <= 0 ||
- x + cw > width || y + ch > height) {
+ if (!WebPCheckCropDimensions(width, height, x, y, cw, ch)) {
return VP8_STATUS_INVALID_PARAM; // out of frame boundary.
}
width = cw;
diff --git a/thirdparty/libwebp/src/dec/frame_dec.c b/thirdparty/libwebp/src/dec/frame_dec.c
index 04609a8e56..91ca1f8609 100644
--- a/thirdparty/libwebp/src/dec/frame_dec.c
+++ b/thirdparty/libwebp/src/dec/frame_dec.c
@@ -705,7 +705,7 @@ static int AllocateMemory(VP8Decoder* const dec) {
+ cache_size + alpha_size + WEBP_ALIGN_CST;
uint8_t* mem;
- if (needed != (size_t)needed) return 0; // check for overflow
+ if (!CheckSizeOverflow(needed)) return 0; // check for overflow
if (needed > dec->mem_size_) {
WebPSafeFree(dec->mem_);
dec->mem_size_ = 0;
diff --git a/thirdparty/libwebp/src/dec/io_dec.c b/thirdparty/libwebp/src/dec/io_dec.c
index e603f19c98..5ef6298886 100644
--- a/thirdparty/libwebp/src/dec/io_dec.c
+++ b/thirdparty/libwebp/src/dec/io_dec.c
@@ -25,21 +25,16 @@
static int EmitYUV(const VP8Io* const io, WebPDecParams* const p) {
WebPDecBuffer* output = p->output;
const WebPYUVABuffer* const buf = &output->u.YUVA;
- uint8_t* const y_dst = buf->y + io->mb_y * buf->y_stride;
- uint8_t* const u_dst = buf->u + (io->mb_y >> 1) * buf->u_stride;
- uint8_t* const v_dst = buf->v + (io->mb_y >> 1) * buf->v_stride;
+ uint8_t* const y_dst = buf->y + (size_t)io->mb_y * buf->y_stride;
+ uint8_t* const u_dst = buf->u + (size_t)(io->mb_y >> 1) * buf->u_stride;
+ uint8_t* const v_dst = buf->v + (size_t)(io->mb_y >> 1) * buf->v_stride;
const int mb_w = io->mb_w;
const int mb_h = io->mb_h;
const int uv_w = (mb_w + 1) / 2;
const int uv_h = (mb_h + 1) / 2;
- int j;
- for (j = 0; j < mb_h; ++j) {
- memcpy(y_dst + j * buf->y_stride, io->y + j * io->y_stride, mb_w);
- }
- for (j = 0; j < uv_h; ++j) {
- memcpy(u_dst + j * buf->u_stride, io->u + j * io->uv_stride, uv_w);
- memcpy(v_dst + j * buf->v_stride, io->v + j * io->uv_stride, uv_w);
- }
+ WebPCopyPlane(io->y, io->y_stride, y_dst, buf->y_stride, mb_w, mb_h);
+ WebPCopyPlane(io->u, io->uv_stride, u_dst, buf->u_stride, uv_w, uv_h);
+ WebPCopyPlane(io->v, io->uv_stride, v_dst, buf->v_stride, uv_w, uv_h);
return io->mb_h;
}
@@ -47,7 +42,7 @@ static int EmitYUV(const VP8Io* const io, WebPDecParams* const p) {
static int EmitSampledRGB(const VP8Io* const io, WebPDecParams* const p) {
WebPDecBuffer* const output = p->output;
WebPRGBABuffer* const buf = &output->u.RGBA;
- uint8_t* const dst = buf->rgba + io->mb_y * buf->stride;
+ uint8_t* const dst = buf->rgba + (size_t)io->mb_y * buf->stride;
WebPSamplerProcessPlane(io->y, io->y_stride,
io->u, io->v, io->uv_stride,
dst, buf->stride, io->mb_w, io->mb_h,
@@ -62,7 +57,7 @@ static int EmitSampledRGB(const VP8Io* const io, WebPDecParams* const p) {
static int EmitFancyRGB(const VP8Io* const io, WebPDecParams* const p) {
int num_lines_out = io->mb_h; // a priori guess
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
- uint8_t* dst = buf->rgba + io->mb_y * buf->stride;
+ uint8_t* dst = buf->rgba + (size_t)io->mb_y * buf->stride;
WebPUpsampleLinePairFunc upsample = WebPUpsamplers[p->output->colorspace];
const uint8_t* cur_y = io->y;
const uint8_t* cur_u = io->u;
@@ -133,7 +128,7 @@ static int EmitAlphaYUV(const VP8Io* const io, WebPDecParams* const p,
const WebPYUVABuffer* const buf = &p->output->u.YUVA;
const int mb_w = io->mb_w;
const int mb_h = io->mb_h;
- uint8_t* dst = buf->a + io->mb_y * buf->a_stride;
+ uint8_t* dst = buf->a + (size_t)io->mb_y * buf->a_stride;
int j;
(void)expected_num_lines_out;
assert(expected_num_lines_out == mb_h);
@@ -186,7 +181,7 @@ static int EmitAlphaRGB(const VP8Io* const io, WebPDecParams* const p,
(colorspace == MODE_ARGB || colorspace == MODE_Argb);
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
int num_rows;
- const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows);
+ const size_t start_y = GetAlphaSourceRow(io, &alpha, &num_rows);
uint8_t* const base_rgba = buf->rgba + start_y * buf->stride;
uint8_t* const dst = base_rgba + (alpha_first ? 0 : 3);
const int has_alpha = WebPDispatchAlpha(alpha, io->width, mb_w,
@@ -210,7 +205,7 @@ static int EmitAlphaRGBA4444(const VP8Io* const io, WebPDecParams* const p,
const WEBP_CSP_MODE colorspace = p->output->colorspace;
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
int num_rows;
- const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows);
+ const size_t start_y = GetAlphaSourceRow(io, &alpha, &num_rows);
uint8_t* const base_rgba = buf->rgba + start_y * buf->stride;
#if (WEBP_SWAP_16BIT_CSP == 1)
uint8_t* alpha_dst = base_rgba;
@@ -276,9 +271,9 @@ static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) {
static int EmitRescaledAlphaYUV(const VP8Io* const io, WebPDecParams* const p,
int expected_num_lines_out) {
const WebPYUVABuffer* const buf = &p->output->u.YUVA;
- uint8_t* const dst_a = buf->a + p->last_y * buf->a_stride;
+ uint8_t* const dst_a = buf->a + (size_t)p->last_y * buf->a_stride;
if (io->a != NULL) {
- uint8_t* const dst_y = buf->y + p->last_y * buf->y_stride;
+ uint8_t* const dst_y = buf->y + (size_t)p->last_y * buf->y_stride;
const int num_lines_out = Rescale(io->a, io->width, io->mb_h, p->scaler_a);
assert(expected_num_lines_out == num_lines_out);
if (num_lines_out > 0) { // unmultiply the Y
@@ -303,46 +298,57 @@ static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) {
const int uv_out_height = (out_height + 1) >> 1;
const int uv_in_width = (io->mb_w + 1) >> 1;
const int uv_in_height = (io->mb_h + 1) >> 1;
- const size_t work_size = 2 * out_width; // scratch memory for luma rescaler
+ // scratch memory for luma rescaler
+ const size_t work_size = 2 * (size_t)out_width;
const size_t uv_work_size = 2 * uv_out_width; // and for each u/v ones
- size_t tmp_size, rescaler_size;
+ uint64_t total_size;
+ size_t rescaler_size;
rescaler_t* work;
WebPRescaler* scalers;
const int num_rescalers = has_alpha ? 4 : 3;
- tmp_size = (work_size + 2 * uv_work_size) * sizeof(*work);
+ total_size = ((uint64_t)work_size + 2 * uv_work_size) * sizeof(*work);
if (has_alpha) {
- tmp_size += work_size * sizeof(*work);
+ total_size += (uint64_t)work_size * sizeof(*work);
}
rescaler_size = num_rescalers * sizeof(*p->scaler_y) + WEBP_ALIGN_CST;
+ total_size += rescaler_size;
+ if (!CheckSizeOverflow(total_size)) {
+ return 0;
+ }
- p->memory = WebPSafeMalloc(1ULL, tmp_size + rescaler_size);
+ p->memory = WebPSafeMalloc(1ULL, (size_t)total_size);
if (p->memory == NULL) {
return 0; // memory error
}
work = (rescaler_t*)p->memory;
- scalers = (WebPRescaler*)WEBP_ALIGN((const uint8_t*)work + tmp_size);
+ scalers = (WebPRescaler*)WEBP_ALIGN(
+ (const uint8_t*)work + total_size - rescaler_size);
p->scaler_y = &scalers[0];
p->scaler_u = &scalers[1];
p->scaler_v = &scalers[2];
p->scaler_a = has_alpha ? &scalers[3] : NULL;
- WebPRescalerInit(p->scaler_y, io->mb_w, io->mb_h,
- buf->y, out_width, out_height, buf->y_stride, 1,
- work);
- WebPRescalerInit(p->scaler_u, uv_in_width, uv_in_height,
- buf->u, uv_out_width, uv_out_height, buf->u_stride, 1,
- work + work_size);
- WebPRescalerInit(p->scaler_v, uv_in_width, uv_in_height,
- buf->v, uv_out_width, uv_out_height, buf->v_stride, 1,
- work + work_size + uv_work_size);
+ if (!WebPRescalerInit(p->scaler_y, io->mb_w, io->mb_h,
+ buf->y, out_width, out_height, buf->y_stride, 1,
+ work) ||
+ !WebPRescalerInit(p->scaler_u, uv_in_width, uv_in_height,
+ buf->u, uv_out_width, uv_out_height, buf->u_stride, 1,
+ work + work_size) ||
+ !WebPRescalerInit(p->scaler_v, uv_in_width, uv_in_height,
+ buf->v, uv_out_width, uv_out_height, buf->v_stride, 1,
+ work + work_size + uv_work_size)) {
+ return 0;
+ }
p->emit = EmitRescaledYUV;
if (has_alpha) {
- WebPRescalerInit(p->scaler_a, io->mb_w, io->mb_h,
- buf->a, out_width, out_height, buf->a_stride, 1,
- work + work_size + 2 * uv_work_size);
+ if (!WebPRescalerInit(p->scaler_a, io->mb_w, io->mb_h,
+ buf->a, out_width, out_height, buf->a_stride, 1,
+ work + work_size + 2 * uv_work_size)) {
+ return 0;
+ }
p->emit_alpha = EmitRescaledAlphaYUV;
WebPInitAlphaProcessing();
}
@@ -356,7 +362,7 @@ static int ExportRGB(WebPDecParams* const p, int y_pos) {
const WebPYUV444Converter convert =
WebPYUV444Converters[p->output->colorspace];
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
- uint8_t* dst = buf->rgba + y_pos * buf->stride;
+ uint8_t* dst = buf->rgba + (size_t)y_pos * buf->stride;
int num_lines_out = 0;
// For RGB rescaling, because of the YUV420, current scan position
// U/V can be +1/-1 line from the Y one. Hence the double test.
@@ -383,15 +389,15 @@ static int EmitRescaledRGB(const VP8Io* const io, WebPDecParams* const p) {
while (j < mb_h) {
const int y_lines_in =
WebPRescalerImport(p->scaler_y, mb_h - j,
- io->y + j * io->y_stride, io->y_stride);
+ io->y + (size_t)j * io->y_stride, io->y_stride);
j += y_lines_in;
if (WebPRescaleNeededLines(p->scaler_u, uv_mb_h - uv_j)) {
- const int u_lines_in =
- WebPRescalerImport(p->scaler_u, uv_mb_h - uv_j,
- io->u + uv_j * io->uv_stride, io->uv_stride);
- const int v_lines_in =
- WebPRescalerImport(p->scaler_v, uv_mb_h - uv_j,
- io->v + uv_j * io->uv_stride, io->uv_stride);
+ const int u_lines_in = WebPRescalerImport(
+ p->scaler_u, uv_mb_h - uv_j, io->u + (size_t)uv_j * io->uv_stride,
+ io->uv_stride);
+ const int v_lines_in = WebPRescalerImport(
+ p->scaler_v, uv_mb_h - uv_j, io->v + (size_t)uv_j * io->uv_stride,
+ io->uv_stride);
(void)v_lines_in; // remove a gcc warning
assert(u_lines_in == v_lines_in);
uv_j += u_lines_in;
@@ -403,7 +409,7 @@ static int EmitRescaledRGB(const VP8Io* const io, WebPDecParams* const p) {
static int ExportAlpha(WebPDecParams* const p, int y_pos, int max_lines_out) {
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
- uint8_t* const base_rgba = buf->rgba + y_pos * buf->stride;
+ uint8_t* const base_rgba = buf->rgba + (size_t)y_pos * buf->stride;
const WEBP_CSP_MODE colorspace = p->output->colorspace;
const int alpha_first =
(colorspace == MODE_ARGB || colorspace == MODE_Argb);
@@ -431,7 +437,7 @@ static int ExportAlpha(WebPDecParams* const p, int y_pos, int max_lines_out) {
static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos,
int max_lines_out) {
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
- uint8_t* const base_rgba = buf->rgba + y_pos * buf->stride;
+ uint8_t* const base_rgba = buf->rgba + (size_t)y_pos * buf->stride;
#if (WEBP_SWAP_16BIT_CSP == 1)
uint8_t* alpha_dst = base_rgba;
#else
@@ -470,7 +476,7 @@ static int EmitRescaledAlphaRGB(const VP8Io* const io, WebPDecParams* const p,
int lines_left = expected_num_out_lines;
const int y_end = p->last_y + lines_left;
while (lines_left > 0) {
- const int row_offset = scaler->src_y - io->mb_y;
+ const int64_t row_offset = (int64_t)scaler->src_y - io->mb_y;
WebPRescalerImport(scaler, io->mb_h + io->mb_y - scaler->src_y,
io->a + row_offset * io->width, io->width);
lines_left -= p->emit_alpha_row(p, y_end - lines_left, lines_left);
@@ -485,51 +491,58 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
const int out_height = io->scaled_height;
const int uv_in_width = (io->mb_w + 1) >> 1;
const int uv_in_height = (io->mb_h + 1) >> 1;
- const size_t work_size = 2 * out_width; // scratch memory for one rescaler
+ // scratch memory for one rescaler
+ const size_t work_size = 2 * (size_t)out_width;
rescaler_t* work; // rescalers work area
uint8_t* tmp; // tmp storage for scaled YUV444 samples before RGB conversion
- size_t tmp_size1, tmp_size2, total_size, rescaler_size;
+ uint64_t tmp_size1, tmp_size2, total_size;
+ size_t rescaler_size;
WebPRescaler* scalers;
const int num_rescalers = has_alpha ? 4 : 3;
- tmp_size1 = 3 * work_size;
- tmp_size2 = 3 * out_width;
- if (has_alpha) {
- tmp_size1 += work_size;
- tmp_size2 += out_width;
- }
+ tmp_size1 = (uint64_t)num_rescalers * work_size;
+ tmp_size2 = (uint64_t)num_rescalers * out_width;
total_size = tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp);
rescaler_size = num_rescalers * sizeof(*p->scaler_y) + WEBP_ALIGN_CST;
+ total_size += rescaler_size;
+ if (!CheckSizeOverflow(total_size)) {
+ return 0;
+ }
- p->memory = WebPSafeMalloc(1ULL, total_size + rescaler_size);
+ p->memory = WebPSafeMalloc(1ULL, (size_t)total_size);
if (p->memory == NULL) {
return 0; // memory error
}
work = (rescaler_t*)p->memory;
tmp = (uint8_t*)(work + tmp_size1);
- scalers = (WebPRescaler*)WEBP_ALIGN((const uint8_t*)work + total_size);
+ scalers = (WebPRescaler*)WEBP_ALIGN(
+ (const uint8_t*)work + total_size - rescaler_size);
p->scaler_y = &scalers[0];
p->scaler_u = &scalers[1];
p->scaler_v = &scalers[2];
p->scaler_a = has_alpha ? &scalers[3] : NULL;
- WebPRescalerInit(p->scaler_y, io->mb_w, io->mb_h,
- tmp + 0 * out_width, out_width, out_height, 0, 1,
- work + 0 * work_size);
- WebPRescalerInit(p->scaler_u, uv_in_width, uv_in_height,
- tmp + 1 * out_width, out_width, out_height, 0, 1,
- work + 1 * work_size);
- WebPRescalerInit(p->scaler_v, uv_in_width, uv_in_height,
- tmp + 2 * out_width, out_width, out_height, 0, 1,
- work + 2 * work_size);
+ if (!WebPRescalerInit(p->scaler_y, io->mb_w, io->mb_h,
+ tmp + 0 * out_width, out_width, out_height, 0, 1,
+ work + 0 * work_size) ||
+ !WebPRescalerInit(p->scaler_u, uv_in_width, uv_in_height,
+ tmp + 1 * out_width, out_width, out_height, 0, 1,
+ work + 1 * work_size) ||
+ !WebPRescalerInit(p->scaler_v, uv_in_width, uv_in_height,
+ tmp + 2 * out_width, out_width, out_height, 0, 1,
+ work + 2 * work_size)) {
+ return 0;
+ }
p->emit = EmitRescaledRGB;
WebPInitYUV444Converters();
if (has_alpha) {
- WebPRescalerInit(p->scaler_a, io->mb_w, io->mb_h,
- tmp + 3 * out_width, out_width, out_height, 0, 1,
- work + 3 * work_size);
+ if (!WebPRescalerInit(p->scaler_a, io->mb_w, io->mb_h,
+ tmp + 3 * out_width, out_width, out_height, 0, 1,
+ work + 3 * work_size)) {
+ return 0;
+ }
p->emit_alpha = EmitRescaledAlphaRGB;
if (p->output->colorspace == MODE_RGBA_4444 ||
p->output->colorspace == MODE_rgbA_4444) {
diff --git a/thirdparty/libwebp/src/dec/vp8_dec.c b/thirdparty/libwebp/src/dec/vp8_dec.c
index 57efb69041..5f405e4c2a 100644
--- a/thirdparty/libwebp/src/dec/vp8_dec.c
+++ b/thirdparty/libwebp/src/dec/vp8_dec.c
@@ -335,7 +335,7 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
io->scaled_width = io->width;
io->scaled_height = io->height;
- io->mb_w = io->width; // sanity check
+ io->mb_w = io->width; // for soundness
io->mb_h = io->height; // ditto
VP8ResetProba(&dec->proba_);
@@ -494,13 +494,11 @@ static int GetCoeffsAlt(VP8BitReader* const br,
return 16;
}
-static WEBP_TSAN_IGNORE_FUNCTION void InitGetCoeffs(void) {
- if (GetCoeffs == NULL) {
- if (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kSlowSSSE3)) {
- GetCoeffs = GetCoeffsAlt;
- } else {
- GetCoeffs = GetCoeffsFast;
- }
+WEBP_DSP_INIT_FUNC(InitGetCoeffs) {
+ if (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kSlowSSSE3)) {
+ GetCoeffs = GetCoeffsAlt;
+ } else {
+ GetCoeffs = GetCoeffsFast;
}
}
diff --git a/thirdparty/libwebp/src/dec/vp8i_dec.h b/thirdparty/libwebp/src/dec/vp8i_dec.h
index 600a684410..20526a87c4 100644
--- a/thirdparty/libwebp/src/dec/vp8i_dec.h
+++ b/thirdparty/libwebp/src/dec/vp8i_dec.h
@@ -31,8 +31,8 @@ extern "C" {
// version numbers
#define DEC_MAJ_VERSION 1
-#define DEC_MIN_VERSION 1
-#define DEC_REV_VERSION 0
+#define DEC_MIN_VERSION 2
+#define DEC_REV_VERSION 1
// YUV-cache parameters. Cache is 32-bytes wide (= one cacheline).
// Constraints are: We need to store one 16x16 block of luma samples (y),
diff --git a/thirdparty/libwebp/src/dec/vp8l_dec.c b/thirdparty/libwebp/src/dec/vp8l_dec.c
index 93615d4ed2..73c3b54fff 100644
--- a/thirdparty/libwebp/src/dec/vp8l_dec.c
+++ b/thirdparty/libwebp/src/dec/vp8l_dec.c
@@ -559,8 +559,11 @@ static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) {
memory += work_size * sizeof(*work);
scaled_data = (uint32_t*)memory;
- WebPRescalerInit(dec->rescaler, in_width, in_height, (uint8_t*)scaled_data,
- out_width, out_height, 0, num_channels, work);
+ if (!WebPRescalerInit(dec->rescaler, in_width, in_height,
+ (uint8_t*)scaled_data, out_width, out_height,
+ 0, num_channels, work)) {
+ return 0;
+ }
return 1;
}
#endif // WEBP_REDUCE_SIZE
@@ -574,13 +577,14 @@ static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) {
static int Export(WebPRescaler* const rescaler, WEBP_CSP_MODE colorspace,
int rgba_stride, uint8_t* const rgba) {
uint32_t* const src = (uint32_t*)rescaler->dst;
+ uint8_t* dst = rgba;
const int dst_width = rescaler->dst_width;
int num_lines_out = 0;
while (WebPRescalerHasPendingOutput(rescaler)) {
- uint8_t* const dst = rgba + num_lines_out * rgba_stride;
WebPRescalerExportRow(rescaler);
WebPMultARGBRow(src, dst_width, 1);
VP8LConvertFromBGRA(src, dst_width, colorspace, dst);
+ dst += rgba_stride;
++num_lines_out;
}
return num_lines_out;
@@ -594,8 +598,8 @@ static int EmitRescaledRowsRGBA(const VP8LDecoder* const dec,
int num_lines_in = 0;
int num_lines_out = 0;
while (num_lines_in < mb_h) {
- uint8_t* const row_in = in + num_lines_in * in_stride;
- uint8_t* const row_out = out + num_lines_out * out_stride;
+ uint8_t* const row_in = in + (uint64_t)num_lines_in * in_stride;
+ uint8_t* const row_out = out + (uint64_t)num_lines_out * out_stride;
const int lines_left = mb_h - num_lines_in;
const int needed_lines = WebPRescaleNeededLines(dec->rescaler, lines_left);
int lines_imported;
@@ -796,7 +800,8 @@ static void ProcessRows(VP8LDecoder* const dec, int row) {
const WebPDecBuffer* const output = dec->output_;
if (WebPIsRGBMode(output->colorspace)) { // convert to RGBA
const WebPRGBABuffer* const buf = &output->u.RGBA;
- uint8_t* const rgba = buf->rgba + dec->last_out_row_ * buf->stride;
+ uint8_t* const rgba =
+ buf->rgba + (int64_t)dec->last_out_row_ * buf->stride;
const int num_rows_out =
#if !defined(WEBP_REDUCE_SIZE)
io->use_scaling ?
@@ -947,7 +952,6 @@ static WEBP_INLINE void CopyBlock8b(uint8_t* const dst, int dist, int length) {
break;
default:
goto Copy;
- break;
}
CopySmallPattern8b(src, dst, length, pattern);
return;
@@ -1515,7 +1519,7 @@ static int AllocateInternalBuffers32b(VP8LDecoder* const dec, int final_width) {
assert(dec->width_ <= final_width);
dec->pixels_ = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(uint32_t));
if (dec->pixels_ == NULL) {
- dec->argb_cache_ = NULL; // for sanity check
+ dec->argb_cache_ = NULL; // for soundness
dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
return 0;
}
@@ -1525,7 +1529,7 @@ static int AllocateInternalBuffers32b(VP8LDecoder* const dec, int final_width) {
static int AllocateInternalBuffers8b(VP8LDecoder* const dec) {
const uint64_t total_num_pixels = (uint64_t)dec->width_ * dec->height_;
- dec->argb_cache_ = NULL; // for sanity check
+ dec->argb_cache_ = NULL; // for soundness
dec->pixels_ = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(uint8_t));
if (dec->pixels_ == NULL) {
dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
@@ -1667,7 +1671,6 @@ int VP8LDecodeImage(VP8LDecoder* const dec) {
VP8Io* io = NULL;
WebPDecParams* params = NULL;
- // Sanity checks.
if (dec == NULL) return 0;
assert(dec->hdr_.huffman_tables_ != NULL);
diff --git a/thirdparty/libwebp/src/dec/webp_dec.c b/thirdparty/libwebp/src/dec/webp_dec.c
index 42d098874d..77a54c55d2 100644
--- a/thirdparty/libwebp/src/dec/webp_dec.c
+++ b/thirdparty/libwebp/src/dec/webp_dec.c
@@ -785,6 +785,13 @@ VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size,
//------------------------------------------------------------------------------
// Cropping and rescaling.
+int WebPCheckCropDimensions(int image_width, int image_height,
+ int x, int y, int w, int h) {
+ return !(x < 0 || y < 0 || w <= 0 || h <= 0 ||
+ x >= image_width || w > image_width || w > image_width - x ||
+ y >= image_height || h > image_height || h > image_height - y);
+}
+
int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
VP8Io* const io, WEBP_CSP_MODE src_colorspace) {
const int W = io->width;
@@ -792,7 +799,7 @@ int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
int x = 0, y = 0, w = W, h = H;
// Cropping
- io->use_cropping = (options != NULL) && (options->use_cropping > 0);
+ io->use_cropping = (options != NULL) && options->use_cropping;
if (io->use_cropping) {
w = options->crop_width;
h = options->crop_height;
@@ -802,7 +809,7 @@ int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
x &= ~1;
y &= ~1;
}
- if (x < 0 || y < 0 || w <= 0 || h <= 0 || x + w > W || y + h > H) {
+ if (!WebPCheckCropDimensions(W, H, x, y, w, h)) {
return 0; // out of frame boundary error
}
}
@@ -814,7 +821,7 @@ int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
io->mb_h = h;
// Scaling
- io->use_scaling = (options != NULL) && (options->use_scaling > 0);
+ io->use_scaling = (options != NULL) && options->use_scaling;
if (io->use_scaling) {
int scaled_width = options->scaled_width;
int scaled_height = options->scaled_height;
@@ -835,8 +842,8 @@ int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
if (io->use_scaling) {
// disable filter (only for large downscaling ratio).
- io->bypass_filtering = (io->scaled_width < W * 3 / 4) &&
- (io->scaled_height < H * 3 / 4);
+ io->bypass_filtering |= (io->scaled_width < W * 3 / 4) &&
+ (io->scaled_height < H * 3 / 4);
io->fancy_upsampling = 0;
}
return 1;
diff --git a/thirdparty/libwebp/src/dec/webpi_dec.h b/thirdparty/libwebp/src/dec/webpi_dec.h
index 24baff5d27..3b97388c71 100644
--- a/thirdparty/libwebp/src/dec/webpi_dec.h
+++ b/thirdparty/libwebp/src/dec/webpi_dec.h
@@ -77,6 +77,10 @@ VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers);
//------------------------------------------------------------------------------
// Misc utils
+// Returns true if crop dimensions are within image bounds.
+int WebPCheckCropDimensions(int image_width, int image_height,
+ int x, int y, int w, int h);
+
// Initializes VP8Io with custom setup, io and teardown functions. The default
// hooks will use the supplied 'params' as io->opaque handle.
void WebPInitCustomIo(WebPDecParams* const params, VP8Io* const io);
diff --git a/thirdparty/libwebp/src/demux/anim_decode.c b/thirdparty/libwebp/src/demux/anim_decode.c
index 05dd707371..2bf4dcffe0 100644
--- a/thirdparty/libwebp/src/demux/anim_decode.c
+++ b/thirdparty/libwebp/src/demux/anim_decode.c
@@ -87,11 +87,19 @@ WebPAnimDecoder* WebPAnimDecoderNewInternal(
int abi_version) {
WebPAnimDecoderOptions options;
WebPAnimDecoder* dec = NULL;
+ WebPBitstreamFeatures features;
if (webp_data == NULL ||
WEBP_ABI_IS_INCOMPATIBLE(abi_version, WEBP_DEMUX_ABI_VERSION)) {
return NULL;
}
+ // Validate the bitstream before doing expensive allocations. The demuxer may
+ // be more tolerant than the decoder.
+ if (WebPGetFeatures(webp_data->bytes, webp_data->size, &features) !=
+ VP8_STATUS_OK) {
+ return NULL;
+ }
+
// Note: calloc() so that the pointer members are initialized to NULL.
dec = (WebPAnimDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec));
if (dec == NULL) goto Error;
@@ -145,7 +153,7 @@ static int ZeroFillCanvas(uint8_t* buf, uint32_t canvas_width,
uint32_t canvas_height) {
const uint64_t size =
(uint64_t)canvas_width * canvas_height * NUM_CHANNELS * sizeof(*buf);
- if (size != (size_t)size) return 0;
+ if (!CheckSizeOverflow(size)) return 0;
memset(buf, 0, (size_t)size);
return 1;
}
@@ -166,7 +174,7 @@ static void ZeroFillFrameRect(uint8_t* buf, int buf_stride, int x_offset,
static int CopyCanvas(const uint8_t* src, uint8_t* dst,
uint32_t width, uint32_t height) {
const uint64_t size = (uint64_t)width * height * NUM_CHANNELS;
- if (size != (size_t)size) return 0;
+ if (!CheckSizeOverflow(size)) return 0;
assert(src != NULL && dst != NULL);
memcpy(dst, src, (size_t)size);
return 1;
@@ -346,12 +354,15 @@ int WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
{
const uint8_t* in = iter.fragment.bytes;
const size_t in_size = iter.fragment.size;
- const size_t out_offset =
- (iter.y_offset * width + iter.x_offset) * NUM_CHANNELS;
+ const uint32_t stride = width * NUM_CHANNELS; // at most 25 + 2 bits
+ const uint64_t out_offset = (uint64_t)iter.y_offset * stride +
+ (uint64_t)iter.x_offset * NUM_CHANNELS; // 53b
+ const uint64_t size = (uint64_t)iter.height * stride; // at most 25 + 27b
WebPDecoderConfig* const config = &dec->config_;
WebPRGBABuffer* const buf = &config->output.u.RGBA;
- buf->stride = NUM_CHANNELS * width;
- buf->size = buf->stride * iter.height;
+ if ((size_t)size != size) goto Error;
+ buf->stride = (int)stride;
+ buf->size = (size_t)size;
buf->rgba = dec->curr_frame_ + out_offset;
if (WebPDecode(in, in_size, config) != VP8_STATUS_OK) {
diff --git a/thirdparty/libwebp/src/demux/demux.c b/thirdparty/libwebp/src/demux/demux.c
index 1b3cc2e0a8..547a7725de 100644
--- a/thirdparty/libwebp/src/demux/demux.c
+++ b/thirdparty/libwebp/src/demux/demux.c
@@ -24,8 +24,8 @@
#include "src/webp/format_constants.h"
#define DMUX_MAJ_VERSION 1
-#define DMUX_MIN_VERSION 1
-#define DMUX_REV_VERSION 0
+#define DMUX_MIN_VERSION 2
+#define DMUX_REV_VERSION 1
typedef struct {
size_t start_; // start location of the data
@@ -221,12 +221,16 @@ static ParseStatus StoreFrame(int frame_num, uint32_t min_size,
const size_t chunk_start_offset = mem->start_;
const uint32_t fourcc = ReadLE32(mem);
const uint32_t payload_size = ReadLE32(mem);
- const uint32_t payload_size_padded = payload_size + (payload_size & 1);
- const size_t payload_available = (payload_size_padded > MemDataSize(mem))
- ? MemDataSize(mem) : payload_size_padded;
- const size_t chunk_size = CHUNK_HEADER_SIZE + payload_available;
+ uint32_t payload_size_padded;
+ size_t payload_available;
+ size_t chunk_size;
if (payload_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR;
+
+ payload_size_padded = payload_size + (payload_size & 1);
+ payload_available = (payload_size_padded > MemDataSize(mem))
+ ? MemDataSize(mem) : payload_size_padded;
+ chunk_size = CHUNK_HEADER_SIZE + payload_available;
if (SizeIsInvalid(mem, payload_size_padded)) return PARSE_ERROR;
if (payload_size_padded > MemDataSize(mem)) status = PARSE_NEED_MORE_DATA;
@@ -312,6 +316,7 @@ static ParseStatus ParseAnimationFrame(
int bits;
MemBuffer* const mem = &dmux->mem_;
Frame* frame;
+ size_t start_offset;
ParseStatus status =
NewFrame(mem, ANMF_CHUNK_SIZE, frame_chunk_size, &frame);
if (status != PARSE_OK) return status;
@@ -332,7 +337,11 @@ static ParseStatus ParseAnimationFrame(
// Store a frame only if the animation flag is set there is some data for
// this frame is available.
+ start_offset = mem->start_;
status = StoreFrame(dmux->num_frames_ + 1, anmf_payload_size, mem, frame);
+ if (status != PARSE_ERROR && mem->start_ - start_offset > anmf_payload_size) {
+ status = PARSE_ERROR;
+ }
if (status != PARSE_ERROR && is_animation && frame->frame_num_ > 0) {
added_frame = AddFrame(dmux, frame);
if (added_frame) {
@@ -446,9 +455,11 @@ static ParseStatus ParseVP8XChunks(WebPDemuxer* const dmux) {
const size_t chunk_start_offset = mem->start_;
const uint32_t fourcc = ReadLE32(mem);
const uint32_t chunk_size = ReadLE32(mem);
- const uint32_t chunk_size_padded = chunk_size + (chunk_size & 1);
+ uint32_t chunk_size_padded;
if (chunk_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR;
+
+ chunk_size_padded = chunk_size + (chunk_size & 1);
if (SizeIsInvalid(mem, chunk_size_padded)) return PARSE_ERROR;
switch (fourcc) {
diff --git a/thirdparty/libwebp/src/dsp/alpha_processing.c b/thirdparty/libwebp/src/dsp/alpha_processing.c
index 819d1391f2..1892929a43 100644
--- a/thirdparty/libwebp/src/dsp/alpha_processing.c
+++ b/thirdparty/libwebp/src/dsp/alpha_processing.c
@@ -157,7 +157,8 @@ void WebPMultARGBRow_C(uint32_t* const ptr, int width, int inverse) {
}
}
-void WebPMultRow_C(uint8_t* const ptr, const uint8_t* const alpha,
+void WebPMultRow_C(uint8_t* WEBP_RESTRICT const ptr,
+ const uint8_t* WEBP_RESTRICT const alpha,
int width, int inverse) {
int x;
for (x = 0; x < width; ++x) {
@@ -178,7 +179,8 @@ void WebPMultRow_C(uint8_t* const ptr, const uint8_t* const alpha,
#undef MFIX
void (*WebPMultARGBRow)(uint32_t* const ptr, int width, int inverse);
-void (*WebPMultRow)(uint8_t* const ptr, const uint8_t* const alpha,
+void (*WebPMultRow)(uint8_t* WEBP_RESTRICT const ptr,
+ const uint8_t* WEBP_RESTRICT const alpha,
int width, int inverse);
//------------------------------------------------------------------------------
@@ -193,8 +195,8 @@ void WebPMultARGBRows(uint8_t* ptr, int stride, int width, int num_rows,
}
}
-void WebPMultRows(uint8_t* ptr, int stride,
- const uint8_t* alpha, int alpha_stride,
+void WebPMultRows(uint8_t* WEBP_RESTRICT ptr, int stride,
+ const uint8_t* WEBP_RESTRICT alpha, int alpha_stride,
int width, int num_rows, int inverse) {
int n;
for (n = 0; n < num_rows; ++n) {
@@ -290,9 +292,9 @@ static void ApplyAlphaMultiply_16b_C(uint8_t* rgba4444,
}
#if !WEBP_NEON_OMIT_C_CODE
-static int DispatchAlpha_C(const uint8_t* alpha, int alpha_stride,
+static int DispatchAlpha_C(const uint8_t* WEBP_RESTRICT alpha, int alpha_stride,
int width, int height,
- uint8_t* dst, int dst_stride) {
+ uint8_t* WEBP_RESTRICT dst, int dst_stride) {
uint32_t alpha_mask = 0xff;
int i, j;
@@ -309,9 +311,10 @@ static int DispatchAlpha_C(const uint8_t* alpha, int alpha_stride,
return (alpha_mask != 0xff);
}
-static void DispatchAlphaToGreen_C(const uint8_t* alpha, int alpha_stride,
- int width, int height,
- uint32_t* dst, int dst_stride) {
+static void DispatchAlphaToGreen_C(const uint8_t* WEBP_RESTRICT alpha,
+ int alpha_stride, int width, int height,
+ uint32_t* WEBP_RESTRICT dst,
+ int dst_stride) {
int i, j;
for (j = 0; j < height; ++j) {
for (i = 0; i < width; ++i) {
@@ -322,9 +325,9 @@ static void DispatchAlphaToGreen_C(const uint8_t* alpha, int alpha_stride,
}
}
-static int ExtractAlpha_C(const uint8_t* argb, int argb_stride,
+static int ExtractAlpha_C(const uint8_t* WEBP_RESTRICT argb, int argb_stride,
int width, int height,
- uint8_t* alpha, int alpha_stride) {
+ uint8_t* WEBP_RESTRICT alpha, int alpha_stride) {
uint8_t alpha_mask = 0xff;
int i, j;
@@ -340,7 +343,8 @@ static int ExtractAlpha_C(const uint8_t* argb, int argb_stride,
return (alpha_mask == 0xff);
}
-static void ExtractGreen_C(const uint32_t* argb, uint8_t* alpha, int size) {
+static void ExtractGreen_C(const uint32_t* WEBP_RESTRICT argb,
+ uint8_t* WEBP_RESTRICT alpha, int size) {
int i;
for (i = 0; i < size; ++i) alpha[i] = argb[i] >> 8;
}
@@ -359,6 +363,11 @@ static int HasAlpha32b_C(const uint8_t* src, int length) {
return 0;
}
+static void AlphaReplace_C(uint32_t* src, int length, uint32_t color) {
+ int x;
+ for (x = 0; x < length; ++x) if ((src[x] >> 24) == 0) src[x] = color;
+}
+
//------------------------------------------------------------------------------
// Simple channel manipulations.
@@ -367,8 +376,11 @@ static WEBP_INLINE uint32_t MakeARGB32(int a, int r, int g, int b) {
}
#ifdef WORDS_BIGENDIAN
-static void PackARGB_C(const uint8_t* a, const uint8_t* r, const uint8_t* g,
- const uint8_t* b, int len, uint32_t* out) {
+static void PackARGB_C(const uint8_t* WEBP_RESTRICT a,
+ const uint8_t* WEBP_RESTRICT r,
+ const uint8_t* WEBP_RESTRICT g,
+ const uint8_t* WEBP_RESTRICT b,
+ int len, uint32_t* WEBP_RESTRICT out) {
int i;
for (i = 0; i < len; ++i) {
out[i] = MakeARGB32(a[4 * i], r[4 * i], g[4 * i], b[4 * i]);
@@ -376,8 +388,10 @@ static void PackARGB_C(const uint8_t* a, const uint8_t* r, const uint8_t* g,
}
#endif
-static void PackRGB_C(const uint8_t* r, const uint8_t* g, const uint8_t* b,
- int len, int step, uint32_t* out) {
+static void PackRGB_C(const uint8_t* WEBP_RESTRICT r,
+ const uint8_t* WEBP_RESTRICT g,
+ const uint8_t* WEBP_RESTRICT b,
+ int len, int step, uint32_t* WEBP_RESTRICT out) {
int i, offset = 0;
for (i = 0; i < len; ++i) {
out[i] = MakeARGB32(0xff, r[offset], g[offset], b[offset]);
@@ -387,19 +401,26 @@ static void PackRGB_C(const uint8_t* r, const uint8_t* g, const uint8_t* b,
void (*WebPApplyAlphaMultiply)(uint8_t*, int, int, int, int);
void (*WebPApplyAlphaMultiply4444)(uint8_t*, int, int, int);
-int (*WebPDispatchAlpha)(const uint8_t*, int, int, int, uint8_t*, int);
-void (*WebPDispatchAlphaToGreen)(const uint8_t*, int, int, int, uint32_t*, int);
-int (*WebPExtractAlpha)(const uint8_t*, int, int, int, uint8_t*, int);
-void (*WebPExtractGreen)(const uint32_t* argb, uint8_t* alpha, int size);
+int (*WebPDispatchAlpha)(const uint8_t* WEBP_RESTRICT, int, int, int,
+ uint8_t* WEBP_RESTRICT, int);
+void (*WebPDispatchAlphaToGreen)(const uint8_t* WEBP_RESTRICT, int, int, int,
+ uint32_t* WEBP_RESTRICT, int);
+int (*WebPExtractAlpha)(const uint8_t* WEBP_RESTRICT, int, int, int,
+ uint8_t* WEBP_RESTRICT, int);
+void (*WebPExtractGreen)(const uint32_t* WEBP_RESTRICT argb,
+ uint8_t* WEBP_RESTRICT alpha, int size);
#ifdef WORDS_BIGENDIAN
void (*WebPPackARGB)(const uint8_t* a, const uint8_t* r, const uint8_t* g,
const uint8_t* b, int, uint32_t*);
#endif
-void (*WebPPackRGB)(const uint8_t* r, const uint8_t* g, const uint8_t* b,
- int len, int step, uint32_t* out);
+void (*WebPPackRGB)(const uint8_t* WEBP_RESTRICT r,
+ const uint8_t* WEBP_RESTRICT g,
+ const uint8_t* WEBP_RESTRICT b,
+ int len, int step, uint32_t* WEBP_RESTRICT out);
int (*WebPHasAlpha8b)(const uint8_t* src, int length);
int (*WebPHasAlpha32b)(const uint8_t* src, int length);
+void (*WebPAlphaReplace)(uint32_t* src, int length, uint32_t color);
//------------------------------------------------------------------------------
// Init function
@@ -428,13 +449,14 @@ WEBP_DSP_INIT_FUNC(WebPInitAlphaProcessing) {
WebPHasAlpha8b = HasAlpha8b_C;
WebPHasAlpha32b = HasAlpha32b_C;
+ WebPAlphaReplace = AlphaReplace_C;
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
if (VP8GetCPUInfo != NULL) {
-#if defined(WEBP_USE_SSE2)
+#if defined(WEBP_HAVE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
WebPInitAlphaProcessingSSE2();
-#if defined(WEBP_USE_SSE41)
+#if defined(WEBP_HAVE_SSE41)
if (VP8GetCPUInfo(kSSE4_1)) {
WebPInitAlphaProcessingSSE41();
}
@@ -448,7 +470,7 @@ WEBP_DSP_INIT_FUNC(WebPInitAlphaProcessing) {
#endif
}
-#if defined(WEBP_USE_NEON)
+#if defined(WEBP_HAVE_NEON)
if (WEBP_NEON_OMIT_C_CODE ||
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
WebPInitAlphaProcessingNEON();
@@ -469,4 +491,5 @@ WEBP_DSP_INIT_FUNC(WebPInitAlphaProcessing) {
assert(WebPPackRGB != NULL);
assert(WebPHasAlpha8b != NULL);
assert(WebPHasAlpha32b != NULL);
+ assert(WebPAlphaReplace != NULL);
}
diff --git a/thirdparty/libwebp/src/dsp/alpha_processing_neon.c b/thirdparty/libwebp/src/dsp/alpha_processing_neon.c
index 9d55421704..9e0ace9421 100644
--- a/thirdparty/libwebp/src/dsp/alpha_processing_neon.c
+++ b/thirdparty/libwebp/src/dsp/alpha_processing_neon.c
@@ -80,9 +80,9 @@ static void ApplyAlphaMultiply_NEON(uint8_t* rgba, int alpha_first,
//------------------------------------------------------------------------------
-static int DispatchAlpha_NEON(const uint8_t* alpha, int alpha_stride,
- int width, int height,
- uint8_t* dst, int dst_stride) {
+static int DispatchAlpha_NEON(const uint8_t* WEBP_RESTRICT alpha,
+ int alpha_stride, int width, int height,
+ uint8_t* WEBP_RESTRICT dst, int dst_stride) {
uint32_t alpha_mask = 0xffffffffu;
uint8x8_t mask8 = vdup_n_u8(0xff);
uint32_t tmp[2];
@@ -112,9 +112,10 @@ static int DispatchAlpha_NEON(const uint8_t* alpha, int alpha_stride,
return (alpha_mask != 0xffffffffu);
}
-static void DispatchAlphaToGreen_NEON(const uint8_t* alpha, int alpha_stride,
- int width, int height,
- uint32_t* dst, int dst_stride) {
+static void DispatchAlphaToGreen_NEON(const uint8_t* WEBP_RESTRICT alpha,
+ int alpha_stride, int width, int height,
+ uint32_t* WEBP_RESTRICT dst,
+ int dst_stride) {
int i, j;
uint8x8x4_t greens; // leave A/R/B channels zero'd.
greens.val[0] = vdup_n_u8(0);
@@ -131,9 +132,9 @@ static void DispatchAlphaToGreen_NEON(const uint8_t* alpha, int alpha_stride,
}
}
-static int ExtractAlpha_NEON(const uint8_t* argb, int argb_stride,
+static int ExtractAlpha_NEON(const uint8_t* WEBP_RESTRICT argb, int argb_stride,
int width, int height,
- uint8_t* alpha, int alpha_stride) {
+ uint8_t* WEBP_RESTRICT alpha, int alpha_stride) {
uint32_t alpha_mask = 0xffffffffu;
uint8x8_t mask8 = vdup_n_u8(0xff);
uint32_t tmp[2];
@@ -161,8 +162,8 @@ static int ExtractAlpha_NEON(const uint8_t* argb, int argb_stride,
return (alpha_mask == 0xffffffffu);
}
-static void ExtractGreen_NEON(const uint32_t* argb,
- uint8_t* alpha, int size) {
+static void ExtractGreen_NEON(const uint32_t* WEBP_RESTRICT argb,
+ uint8_t* WEBP_RESTRICT alpha, int size) {
int i;
for (i = 0; i + 16 <= size; i += 16) {
const uint8x16x4_t rgbX = vld4q_u8((const uint8_t*)(argb + i));
diff --git a/thirdparty/libwebp/src/dsp/alpha_processing_sse2.c b/thirdparty/libwebp/src/dsp/alpha_processing_sse2.c
index 2871c56d84..a5f8c9f7c7 100644
--- a/thirdparty/libwebp/src/dsp/alpha_processing_sse2.c
+++ b/thirdparty/libwebp/src/dsp/alpha_processing_sse2.c
@@ -18,9 +18,9 @@
//------------------------------------------------------------------------------
-static int DispatchAlpha_SSE2(const uint8_t* alpha, int alpha_stride,
- int width, int height,
- uint8_t* dst, int dst_stride) {
+static int DispatchAlpha_SSE2(const uint8_t* WEBP_RESTRICT alpha,
+ int alpha_stride, int width, int height,
+ uint8_t* WEBP_RESTRICT dst, int dst_stride) {
// alpha_and stores an 'and' operation of all the alpha[] values. The final
// value is not 0xff if any of the alpha[] is not equal to 0xff.
uint32_t alpha_and = 0xff;
@@ -72,9 +72,10 @@ static int DispatchAlpha_SSE2(const uint8_t* alpha, int alpha_stride,
return (alpha_and != 0xff);
}
-static void DispatchAlphaToGreen_SSE2(const uint8_t* alpha, int alpha_stride,
- int width, int height,
- uint32_t* dst, int dst_stride) {
+static void DispatchAlphaToGreen_SSE2(const uint8_t* WEBP_RESTRICT alpha,
+ int alpha_stride, int width, int height,
+ uint32_t* WEBP_RESTRICT dst,
+ int dst_stride) {
int i, j;
const __m128i zero = _mm_setzero_si128();
const int limit = width & ~15;
@@ -98,9 +99,9 @@ static void DispatchAlphaToGreen_SSE2(const uint8_t* alpha, int alpha_stride,
}
}
-static int ExtractAlpha_SSE2(const uint8_t* argb, int argb_stride,
+static int ExtractAlpha_SSE2(const uint8_t* WEBP_RESTRICT argb, int argb_stride,
int width, int height,
- uint8_t* alpha, int alpha_stride) {
+ uint8_t* WEBP_RESTRICT alpha, int alpha_stride) {
// alpha_and stores an 'and' operation of all the alpha[] values. The final
// value is not 0xff if any of the alpha[] is not equal to 0xff.
uint32_t alpha_and = 0xff;
@@ -265,6 +266,27 @@ static int HasAlpha32b_SSE2(const uint8_t* src, int length) {
return 0;
}
+static void AlphaReplace_SSE2(uint32_t* src, int length, uint32_t color) {
+ const __m128i m_color = _mm_set1_epi32(color);
+ const __m128i zero = _mm_setzero_si128();
+ int i = 0;
+ for (; i + 8 <= length; i += 8) {
+ const __m128i a0 = _mm_loadu_si128((const __m128i*)(src + i + 0));
+ const __m128i a1 = _mm_loadu_si128((const __m128i*)(src + i + 4));
+ const __m128i b0 = _mm_srai_epi32(a0, 24);
+ const __m128i b1 = _mm_srai_epi32(a1, 24);
+ const __m128i c0 = _mm_cmpeq_epi32(b0, zero);
+ const __m128i c1 = _mm_cmpeq_epi32(b1, zero);
+ const __m128i d0 = _mm_and_si128(c0, m_color);
+ const __m128i d1 = _mm_and_si128(c1, m_color);
+ const __m128i e0 = _mm_andnot_si128(c0, a0);
+ const __m128i e1 = _mm_andnot_si128(c1, a1);
+ _mm_storeu_si128((__m128i*)(src + i + 0), _mm_or_si128(d0, e0));
+ _mm_storeu_si128((__m128i*)(src + i + 4), _mm_or_si128(d1, e1));
+ }
+ for (; i < length; ++i) if ((src[i] >> 24) == 0) src[i] = color;
+}
+
// -----------------------------------------------------------------------------
// Apply alpha value to rows
@@ -296,7 +318,8 @@ static void MultARGBRow_SSE2(uint32_t* const ptr, int width, int inverse) {
if (width > 0) WebPMultARGBRow_C(ptr + x, width, inverse);
}
-static void MultRow_SSE2(uint8_t* const ptr, const uint8_t* const alpha,
+static void MultRow_SSE2(uint8_t* WEBP_RESTRICT const ptr,
+ const uint8_t* WEBP_RESTRICT const alpha,
int width, int inverse) {
int x = 0;
if (!inverse) {
@@ -334,6 +357,7 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessingSSE2(void) {
WebPHasAlpha8b = HasAlpha8b_SSE2;
WebPHasAlpha32b = HasAlpha32b_SSE2;
+ WebPAlphaReplace = AlphaReplace_SSE2;
}
#else // !WEBP_USE_SSE2
diff --git a/thirdparty/libwebp/src/dsp/alpha_processing_sse41.c b/thirdparty/libwebp/src/dsp/alpha_processing_sse41.c
index 56040f9c88..cdf877ce49 100644
--- a/thirdparty/libwebp/src/dsp/alpha_processing_sse41.c
+++ b/thirdparty/libwebp/src/dsp/alpha_processing_sse41.c
@@ -19,9 +19,9 @@
//------------------------------------------------------------------------------
-static int ExtractAlpha_SSE41(const uint8_t* argb, int argb_stride,
- int width, int height,
- uint8_t* alpha, int alpha_stride) {
+static int ExtractAlpha_SSE41(const uint8_t* WEBP_RESTRICT argb,
+ int argb_stride, int width, int height,
+ uint8_t* WEBP_RESTRICT alpha, int alpha_stride) {
// alpha_and stores an 'and' operation of all the alpha[] values. The final
// value is not 0xff if any of the alpha[] is not equal to 0xff.
uint32_t alpha_and = 0xff;
diff --git a/thirdparty/libwebp/src/dsp/cost.c b/thirdparty/libwebp/src/dsp/cost.c
index cc681cdd4b..460ec4f2a7 100644
--- a/thirdparty/libwebp/src/dsp/cost.c
+++ b/thirdparty/libwebp/src/dsp/cost.c
@@ -395,12 +395,12 @@ WEBP_DSP_INIT_FUNC(VP8EncDspCostInit) {
VP8EncDspCostInitMIPSdspR2();
}
#endif
-#if defined(WEBP_USE_SSE2)
+#if defined(WEBP_HAVE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
VP8EncDspCostInitSSE2();
}
#endif
-#if defined(WEBP_USE_NEON)
+#if defined(WEBP_HAVE_NEON)
if (VP8GetCPUInfo(kNEON)) {
VP8EncDspCostInitNEON();
}
diff --git a/thirdparty/libwebp/src/dsp/cpu.c b/thirdparty/libwebp/src/dsp/cpu.c
index 0fa5b6a5ce..3145e190a4 100644
--- a/thirdparty/libwebp/src/dsp/cpu.c
+++ b/thirdparty/libwebp/src/dsp/cpu.c
@@ -55,12 +55,18 @@ static WEBP_INLINE void GetCPUInfo(int cpu_info[4], int info_type) {
: "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
: "a"(info_type), "c"(0));
}
-#elif (defined(_M_X64) || defined(_M_IX86)) && \
- defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 150030729 // >= VS2008 SP1
+#elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86))
+
+#if defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 150030729 // >= VS2008 SP1
#include <intrin.h>
#define GetCPUInfo(info, type) __cpuidex(info, type, 0) // set ecx=0
-#elif defined(WEBP_MSC_SSE2)
+#define WEBP_HAVE_MSC_CPUID
+#elif _MSC_VER > 1310
+#include <intrin.h>
#define GetCPUInfo __cpuid
+#define WEBP_HAVE_MSC_CPUID
+#endif
+
#endif
// NaCl has no support for xgetbv or the raw opcode.
@@ -94,7 +100,7 @@ static WEBP_INLINE uint64_t xgetbv(void) {
#define xgetbv() 0U // no AVX for older x64 or unrecognized toolchains.
#endif
-#if defined(__i386__) || defined(__x86_64__) || defined(WEBP_MSC_SSE2)
+#if defined(__i386__) || defined(__x86_64__) || defined(WEBP_HAVE_MSC_CPUID)
// helper function for run-time detection of slow SSSE3 platforms
static int CheckSlowModel(int info) {
@@ -179,9 +185,34 @@ static int AndroidCPUInfo(CPUFeature feature) {
return 0;
}
VP8CPUInfo VP8GetCPUInfo = AndroidCPUInfo;
-#elif defined(WEBP_USE_NEON)
-// define a dummy function to enable turning off NEON at runtime by setting
-// VP8DecGetCPUInfo = NULL
+#elif defined(EMSCRIPTEN) // also needs to be before generic NEON test
+// Use compile flags as an indicator of SIMD support instead of a runtime check.
+static int wasmCPUInfo(CPUFeature feature) {
+ switch (feature) {
+#ifdef WEBP_HAVE_SSE2
+ case kSSE2:
+ return 1;
+#endif
+#ifdef WEBP_HAVE_SSE41
+ case kSSE3:
+ case kSlowSSSE3:
+ case kSSE4_1:
+ return 1;
+#endif
+#ifdef WEBP_HAVE_NEON
+ case kNEON:
+ return 1;
+#endif
+ default:
+ break;
+ }
+ return 0;
+}
+VP8CPUInfo VP8GetCPUInfo = wasmCPUInfo;
+#elif defined(WEBP_HAVE_NEON)
+// In most cases this function doesn't check for NEON support (it's assumed by
+// the configuration), but enables turning off NEON at runtime, for testing
+// purposes, by setting VP8DecGetCPUInfo = NULL.
static int armCPUInfo(CPUFeature feature) {
if (feature != kNEON) return 0;
#if defined(__linux__) && defined(WEBP_HAVE_NEON_RTCD)
diff --git a/thirdparty/libwebp/src/dsp/dec.c b/thirdparty/libwebp/src/dsp/dec.c
index 1119842dd3..537c701282 100644
--- a/thirdparty/libwebp/src/dsp/dec.c
+++ b/thirdparty/libwebp/src/dsp/dec.c
@@ -807,10 +807,10 @@ WEBP_DSP_INIT_FUNC(VP8DspInit) {
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
if (VP8GetCPUInfo != NULL) {
-#if defined(WEBP_USE_SSE2)
+#if defined(WEBP_HAVE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
VP8DspInitSSE2();
-#if defined(WEBP_USE_SSE41)
+#if defined(WEBP_HAVE_SSE41)
if (VP8GetCPUInfo(kSSE4_1)) {
VP8DspInitSSE41();
}
@@ -834,7 +834,7 @@ WEBP_DSP_INIT_FUNC(VP8DspInit) {
#endif
}
-#if defined(WEBP_USE_NEON)
+#if defined(WEBP_HAVE_NEON)
if (WEBP_NEON_OMIT_C_CODE ||
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
VP8DspInitNEON();
diff --git a/thirdparty/libwebp/src/dsp/dec_neon.c b/thirdparty/libwebp/src/dsp/dec_neon.c
index 239ec4167e..fa851707e2 100644
--- a/thirdparty/libwebp/src/dsp/dec_neon.c
+++ b/thirdparty/libwebp/src/dsp/dec_neon.c
@@ -1283,12 +1283,12 @@ static void DC4_NEON(uint8_t* dst) { // DC
const uint8x8_t A = vld1_u8(dst - BPS); // top row
const uint16x4_t p0 = vpaddl_u8(A); // cascading summation of the top
const uint16x4_t p1 = vpadd_u16(p0, p0);
- const uint16x8_t L0 = vmovl_u8(vld1_u8(dst + 0 * BPS - 1));
- const uint16x8_t L1 = vmovl_u8(vld1_u8(dst + 1 * BPS - 1));
- const uint16x8_t L2 = vmovl_u8(vld1_u8(dst + 2 * BPS - 1));
- const uint16x8_t L3 = vmovl_u8(vld1_u8(dst + 3 * BPS - 1));
- const uint16x8_t s0 = vaddq_u16(L0, L1);
- const uint16x8_t s1 = vaddq_u16(L2, L3);
+ const uint8x8_t L0 = vld1_u8(dst + 0 * BPS - 1);
+ const uint8x8_t L1 = vld1_u8(dst + 1 * BPS - 1);
+ const uint8x8_t L2 = vld1_u8(dst + 2 * BPS - 1);
+ const uint8x8_t L3 = vld1_u8(dst + 3 * BPS - 1);
+ const uint16x8_t s0 = vaddl_u8(L0, L1);
+ const uint16x8_t s1 = vaddl_u8(L2, L3);
const uint16x8_t s01 = vaddq_u16(s0, s1);
const uint16x8_t sum = vaddq_u16(s01, vcombine_u16(p1, p1));
const uint8x8_t dc0 = vrshrn_n_u16(sum, 3); // (sum + 4) >> 3
@@ -1429,8 +1429,7 @@ static WEBP_INLINE void DC8_NEON(uint8_t* dst, int do_top, int do_left) {
if (do_top) {
const uint8x8_t A = vld1_u8(dst - BPS); // top row
#if defined(__aarch64__)
- const uint16x8_t B = vmovl_u8(A);
- const uint16_t p2 = vaddvq_u16(B);
+ const uint16_t p2 = vaddlv_u8(A);
sum_top = vdupq_n_u16(p2);
#else
const uint16x4_t p0 = vpaddl_u8(A); // cascading summation of the top
@@ -1441,18 +1440,18 @@ static WEBP_INLINE void DC8_NEON(uint8_t* dst, int do_top, int do_left) {
}
if (do_left) {
- const uint16x8_t L0 = vmovl_u8(vld1_u8(dst + 0 * BPS - 1));
- const uint16x8_t L1 = vmovl_u8(vld1_u8(dst + 1 * BPS - 1));
- const uint16x8_t L2 = vmovl_u8(vld1_u8(dst + 2 * BPS - 1));
- const uint16x8_t L3 = vmovl_u8(vld1_u8(dst + 3 * BPS - 1));
- const uint16x8_t L4 = vmovl_u8(vld1_u8(dst + 4 * BPS - 1));
- const uint16x8_t L5 = vmovl_u8(vld1_u8(dst + 5 * BPS - 1));
- const uint16x8_t L6 = vmovl_u8(vld1_u8(dst + 6 * BPS - 1));
- const uint16x8_t L7 = vmovl_u8(vld1_u8(dst + 7 * BPS - 1));
- const uint16x8_t s0 = vaddq_u16(L0, L1);
- const uint16x8_t s1 = vaddq_u16(L2, L3);
- const uint16x8_t s2 = vaddq_u16(L4, L5);
- const uint16x8_t s3 = vaddq_u16(L6, L7);
+ const uint8x8_t L0 = vld1_u8(dst + 0 * BPS - 1);
+ const uint8x8_t L1 = vld1_u8(dst + 1 * BPS - 1);
+ const uint8x8_t L2 = vld1_u8(dst + 2 * BPS - 1);
+ const uint8x8_t L3 = vld1_u8(dst + 3 * BPS - 1);
+ const uint8x8_t L4 = vld1_u8(dst + 4 * BPS - 1);
+ const uint8x8_t L5 = vld1_u8(dst + 5 * BPS - 1);
+ const uint8x8_t L6 = vld1_u8(dst + 6 * BPS - 1);
+ const uint8x8_t L7 = vld1_u8(dst + 7 * BPS - 1);
+ const uint16x8_t s0 = vaddl_u8(L0, L1);
+ const uint16x8_t s1 = vaddl_u8(L2, L3);
+ const uint16x8_t s2 = vaddl_u8(L4, L5);
+ const uint16x8_t s3 = vaddl_u8(L6, L7);
const uint16x8_t s01 = vaddq_u16(s0, s1);
const uint16x8_t s23 = vaddq_u16(s2, s3);
sum_left = vaddq_u16(s01, s23);
@@ -1512,29 +1511,34 @@ static WEBP_INLINE void DC16_NEON(uint8_t* dst, int do_top, int do_left) {
if (do_top) {
const uint8x16_t A = vld1q_u8(dst - BPS); // top row
+#if defined(__aarch64__)
+ const uint16_t p3 = vaddlvq_u8(A);
+ sum_top = vdupq_n_u16(p3);
+#else
const uint16x8_t p0 = vpaddlq_u8(A); // cascading summation of the top
const uint16x4_t p1 = vadd_u16(vget_low_u16(p0), vget_high_u16(p0));
const uint16x4_t p2 = vpadd_u16(p1, p1);
const uint16x4_t p3 = vpadd_u16(p2, p2);
sum_top = vcombine_u16(p3, p3);
+#endif
}
if (do_left) {
int i;
sum_left = vdupq_n_u16(0);
for (i = 0; i < 16; i += 8) {
- const uint16x8_t L0 = vmovl_u8(vld1_u8(dst + (i + 0) * BPS - 1));
- const uint16x8_t L1 = vmovl_u8(vld1_u8(dst + (i + 1) * BPS - 1));
- const uint16x8_t L2 = vmovl_u8(vld1_u8(dst + (i + 2) * BPS - 1));
- const uint16x8_t L3 = vmovl_u8(vld1_u8(dst + (i + 3) * BPS - 1));
- const uint16x8_t L4 = vmovl_u8(vld1_u8(dst + (i + 4) * BPS - 1));
- const uint16x8_t L5 = vmovl_u8(vld1_u8(dst + (i + 5) * BPS - 1));
- const uint16x8_t L6 = vmovl_u8(vld1_u8(dst + (i + 6) * BPS - 1));
- const uint16x8_t L7 = vmovl_u8(vld1_u8(dst + (i + 7) * BPS - 1));
- const uint16x8_t s0 = vaddq_u16(L0, L1);
- const uint16x8_t s1 = vaddq_u16(L2, L3);
- const uint16x8_t s2 = vaddq_u16(L4, L5);
- const uint16x8_t s3 = vaddq_u16(L6, L7);
+ const uint8x8_t L0 = vld1_u8(dst + (i + 0) * BPS - 1);
+ const uint8x8_t L1 = vld1_u8(dst + (i + 1) * BPS - 1);
+ const uint8x8_t L2 = vld1_u8(dst + (i + 2) * BPS - 1);
+ const uint8x8_t L3 = vld1_u8(dst + (i + 3) * BPS - 1);
+ const uint8x8_t L4 = vld1_u8(dst + (i + 4) * BPS - 1);
+ const uint8x8_t L5 = vld1_u8(dst + (i + 5) * BPS - 1);
+ const uint8x8_t L6 = vld1_u8(dst + (i + 6) * BPS - 1);
+ const uint8x8_t L7 = vld1_u8(dst + (i + 7) * BPS - 1);
+ const uint16x8_t s0 = vaddl_u8(L0, L1);
+ const uint16x8_t s1 = vaddl_u8(L2, L3);
+ const uint16x8_t s2 = vaddl_u8(L4, L5);
+ const uint16x8_t s3 = vaddl_u8(L6, L7);
const uint16x8_t s01 = vaddq_u16(s0, s1);
const uint16x8_t s23 = vaddq_u16(s2, s3);
const uint16x8_t sum = vaddq_u16(s01, s23);
diff --git a/thirdparty/libwebp/src/dsp/dsp.h b/thirdparty/libwebp/src/dsp/dsp.h
index a784de334a..513e159bb3 100644
--- a/thirdparty/libwebp/src/dsp/dsp.h
+++ b/thirdparty/libwebp/src/dsp/dsp.h
@@ -27,6 +27,23 @@ extern "C" {
#define BPS 32 // this is the common stride for enc/dec
//------------------------------------------------------------------------------
+// WEBP_RESTRICT
+
+// Declares a pointer with the restrict type qualifier if available.
+// This allows code to hint to the compiler that only this pointer references a
+// particular object or memory region within the scope of the block in which it
+// is declared. This may allow for improved optimizations due to the lack of
+// pointer aliasing. See also:
+// https://en.cppreference.com/w/c/language/restrict
+#if defined(__GNUC__)
+#define WEBP_RESTRICT __restrict__
+#elif defined(_MSC_VER)
+#define WEBP_RESTRICT __restrict
+#else
+#define WEBP_RESTRICT
+#endif
+
+//------------------------------------------------------------------------------
// CPU detection
#if defined(__GNUC__)
@@ -51,9 +68,7 @@ extern "C" {
# define __has_builtin(x) 0
#endif
-// for now, none of the optimizations below are available in emscripten
-#if !defined(EMSCRIPTEN)
-
+#if !defined(HAVE_CONFIG_H)
#if defined(_MSC_VER) && _MSC_VER > 1310 && \
(defined(_M_X64) || defined(_M_IX86))
#define WEBP_MSC_SSE2 // Visual C++ SSE2 targets
@@ -63,23 +78,37 @@ extern "C" {
(defined(_M_X64) || defined(_M_IX86))
#define WEBP_MSC_SSE41 // Visual C++ SSE4.1 targets
#endif
+#endif
// WEBP_HAVE_* are used to indicate the presence of the instruction set in dsp
// files without intrinsics, allowing the corresponding Init() to be called.
// Files containing intrinsics will need to be built targeting the instruction
// set so should succeed on one of the earlier tests.
-#if defined(__SSE2__) || defined(WEBP_MSC_SSE2) || defined(WEBP_HAVE_SSE2)
+#if (defined(__SSE2__) || defined(WEBP_MSC_SSE2)) && \
+ (!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_SSE2))
#define WEBP_USE_SSE2
#endif
-#if defined(__SSE4_1__) || defined(WEBP_MSC_SSE41) || defined(WEBP_HAVE_SSE41)
+#if defined(WEBP_USE_SSE2) && !defined(WEBP_HAVE_SSE2)
+#define WEBP_HAVE_SSE2
+#endif
+
+#if (defined(__SSE4_1__) || defined(WEBP_MSC_SSE41)) && \
+ (!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_SSE41))
#define WEBP_USE_SSE41
#endif
+#if defined(WEBP_USE_SSE41) && !defined(WEBP_HAVE_SSE41)
+#define WEBP_HAVE_SSE41
+#endif
+
+#undef WEBP_MSC_SSE41
+#undef WEBP_MSC_SSE2
+
// The intrinsics currently cause compiler errors with arm-nacl-gcc and the
// inline assembly would need to be modified for use with Native Client.
-#if (defined(__ARM_NEON__) || \
- defined(__aarch64__) || defined(WEBP_HAVE_NEON)) && \
+#if ((defined(__ARM_NEON__) || defined(__aarch64__)) && \
+ (!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_NEON))) && \
!defined(__native_client__)
#define WEBP_USE_NEON
#endif
@@ -95,6 +124,10 @@ extern "C" {
#define WEBP_USE_INTRINSICS
#endif
+#if defined(WEBP_USE_NEON) && !defined(WEBP_HAVE_NEON)
+#define WEBP_HAVE_NEON
+#endif
+
#if defined(__mips__) && !defined(__mips64) && \
defined(__mips_isa_rev) && (__mips_isa_rev >= 1) && (__mips_isa_rev < 6)
#define WEBP_USE_MIPS32
@@ -110,13 +143,11 @@ extern "C" {
#define WEBP_USE_MSA
#endif
-#endif /* EMSCRIPTEN */
-
#ifndef WEBP_DSP_OMIT_C_CODE
#define WEBP_DSP_OMIT_C_CODE 1
#endif
-#if (defined(__aarch64__) || defined(__ARM_NEON__)) && WEBP_DSP_OMIT_C_CODE
+#if defined(WEBP_USE_NEON) && WEBP_DSP_OMIT_C_CODE
#define WEBP_NEON_OMIT_C_CODE 1
#else
#define WEBP_NEON_OMIT_C_CODE 0
@@ -193,6 +224,12 @@ extern "C" {
#endif
#endif
+// If 'ptr' is NULL, returns NULL. Otherwise returns 'ptr + off'.
+// Prevents undefined behavior sanitizer nullptr-with-nonzero-offset warning.
+#if !defined(WEBP_OFFSET_PTR)
+#define WEBP_OFFSET_PTR(ptr, off) (((ptr) == NULL) ? NULL : ((ptr) + (off)))
+#endif
+
// Regularize the definition of WEBP_SWAP_16BIT_CSP (backward compatibility)
#if !defined(WEBP_SWAP_16BIT_CSP)
#define WEBP_SWAP_16BIT_CSP 0
@@ -572,26 +609,29 @@ extern void (*WebPApplyAlphaMultiply4444)(
// Dispatch the values from alpha[] plane to the ARGB destination 'dst'.
// Returns true if alpha[] plane has non-trivial values different from 0xff.
-extern int (*WebPDispatchAlpha)(const uint8_t* alpha, int alpha_stride,
- int width, int height,
- uint8_t* dst, int dst_stride);
+extern int (*WebPDispatchAlpha)(const uint8_t* WEBP_RESTRICT alpha,
+ int alpha_stride, int width, int height,
+ uint8_t* WEBP_RESTRICT dst, int dst_stride);
// Transfer packed 8b alpha[] values to green channel in dst[], zero'ing the
// A/R/B values. 'dst_stride' is the stride for dst[] in uint32_t units.
-extern void (*WebPDispatchAlphaToGreen)(const uint8_t* alpha, int alpha_stride,
- int width, int height,
- uint32_t* dst, int dst_stride);
+extern void (*WebPDispatchAlphaToGreen)(const uint8_t* WEBP_RESTRICT alpha,
+ int alpha_stride, int width, int height,
+ uint32_t* WEBP_RESTRICT dst,
+ int dst_stride);
// Extract the alpha values from 32b values in argb[] and pack them into alpha[]
// (this is the opposite of WebPDispatchAlpha).
// Returns true if there's only trivial 0xff alpha values.
-extern int (*WebPExtractAlpha)(const uint8_t* argb, int argb_stride,
- int width, int height,
- uint8_t* alpha, int alpha_stride);
+extern int (*WebPExtractAlpha)(const uint8_t* WEBP_RESTRICT argb,
+ int argb_stride, int width, int height,
+ uint8_t* WEBP_RESTRICT alpha,
+ int alpha_stride);
// Extract the green values from 32b values in argb[] and pack them into alpha[]
// (this is the opposite of WebPDispatchAlphaToGreen).
-extern void (*WebPExtractGreen)(const uint32_t* argb, uint8_t* alpha, int size);
+extern void (*WebPExtractGreen)(const uint32_t* WEBP_RESTRICT argb,
+ uint8_t* WEBP_RESTRICT alpha, int size);
// Pre-Multiply operation transforms x into x * A / 255 (where x=Y,R,G or B).
// Un-Multiply operation transforms x into x * 255 / A.
@@ -604,34 +644,42 @@ void WebPMultARGBRows(uint8_t* ptr, int stride, int width, int num_rows,
int inverse);
// Same for a row of single values, with side alpha values.
-extern void (*WebPMultRow)(uint8_t* const ptr, const uint8_t* const alpha,
+extern void (*WebPMultRow)(uint8_t* WEBP_RESTRICT const ptr,
+ const uint8_t* WEBP_RESTRICT const alpha,
int width, int inverse);
// Same a WebPMultRow(), but for several 'num_rows' rows.
-void WebPMultRows(uint8_t* ptr, int stride,
- const uint8_t* alpha, int alpha_stride,
+void WebPMultRows(uint8_t* WEBP_RESTRICT ptr, int stride,
+ const uint8_t* WEBP_RESTRICT alpha, int alpha_stride,
int width, int num_rows, int inverse);
// Plain-C versions, used as fallback by some implementations.
-void WebPMultRow_C(uint8_t* const ptr, const uint8_t* const alpha,
+void WebPMultRow_C(uint8_t* WEBP_RESTRICT const ptr,
+ const uint8_t* WEBP_RESTRICT const alpha,
int width, int inverse);
void WebPMultARGBRow_C(uint32_t* const ptr, int width, int inverse);
#ifdef WORDS_BIGENDIAN
// ARGB packing function: a/r/g/b input is rgba or bgra order.
-extern void (*WebPPackARGB)(const uint8_t* a, const uint8_t* r,
- const uint8_t* g, const uint8_t* b, int len,
- uint32_t* out);
+extern void (*WebPPackARGB)(const uint8_t* WEBP_RESTRICT a,
+ const uint8_t* WEBP_RESTRICT r,
+ const uint8_t* WEBP_RESTRICT g,
+ const uint8_t* WEBP_RESTRICT b,
+ int len, uint32_t* WEBP_RESTRICT out);
#endif
// RGB packing function. 'step' can be 3 or 4. r/g/b input is rgb or bgr order.
-extern void (*WebPPackRGB)(const uint8_t* r, const uint8_t* g, const uint8_t* b,
- int len, int step, uint32_t* out);
+extern void (*WebPPackRGB)(const uint8_t* WEBP_RESTRICT r,
+ const uint8_t* WEBP_RESTRICT g,
+ const uint8_t* WEBP_RESTRICT b,
+ int len, int step, uint32_t* WEBP_RESTRICT out);
// This function returns true if src[i] contains a value different from 0xff.
extern int (*WebPHasAlpha8b)(const uint8_t* src, int length);
// This function returns true if src[4*i] contains a value different from 0xff.
extern int (*WebPHasAlpha32b)(const uint8_t* src, int length);
+// replaces transparent values in src[] by 'color'.
+extern void (*WebPAlphaReplace)(uint32_t* src, int length, uint32_t color);
// To be called first before using the above.
void WebPInitAlphaProcessing(void);
diff --git a/thirdparty/libwebp/src/dsp/enc.c b/thirdparty/libwebp/src/dsp/enc.c
index 2fddbc4c52..ea47a3fd95 100644
--- a/thirdparty/libwebp/src/dsp/enc.c
+++ b/thirdparty/libwebp/src/dsp/enc.c
@@ -773,10 +773,10 @@ WEBP_DSP_INIT_FUNC(VP8EncDspInit) {
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
if (VP8GetCPUInfo != NULL) {
-#if defined(WEBP_USE_SSE2)
+#if defined(WEBP_HAVE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
VP8EncDspInitSSE2();
-#if defined(WEBP_USE_SSE41)
+#if defined(WEBP_HAVE_SSE41)
if (VP8GetCPUInfo(kSSE4_1)) {
VP8EncDspInitSSE41();
}
@@ -800,7 +800,7 @@ WEBP_DSP_INIT_FUNC(VP8EncDspInit) {
#endif
}
-#if defined(WEBP_USE_NEON)
+#if defined(WEBP_HAVE_NEON)
if (WEBP_NEON_OMIT_C_CODE ||
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
VP8EncDspInitNEON();
diff --git a/thirdparty/libwebp/src/dsp/filters.c b/thirdparty/libwebp/src/dsp/filters.c
index 9e910d99c9..4506567ba3 100644
--- a/thirdparty/libwebp/src/dsp/filters.c
+++ b/thirdparty/libwebp/src/dsp/filters.c
@@ -254,7 +254,7 @@ WEBP_DSP_INIT_FUNC(VP8FiltersInit) {
#endif
if (VP8GetCPUInfo != NULL) {
-#if defined(WEBP_USE_SSE2)
+#if defined(WEBP_HAVE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
VP8FiltersInitSSE2();
}
@@ -271,7 +271,7 @@ WEBP_DSP_INIT_FUNC(VP8FiltersInit) {
#endif
}
-#if defined(WEBP_USE_NEON)
+#if defined(WEBP_HAVE_NEON)
if (WEBP_NEON_OMIT_C_CODE ||
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
VP8FiltersInitNEON();
diff --git a/thirdparty/libwebp/src/dsp/filters_sse2.c b/thirdparty/libwebp/src/dsp/filters_sse2.c
index 4b3f2d020f..5c33ec15e2 100644
--- a/thirdparty/libwebp/src/dsp/filters_sse2.c
+++ b/thirdparty/libwebp/src/dsp/filters_sse2.c
@@ -320,7 +320,12 @@ extern void VP8FiltersInitSSE2(void);
WEBP_TSAN_IGNORE_FUNCTION void VP8FiltersInitSSE2(void) {
WebPUnfilters[WEBP_FILTER_HORIZONTAL] = HorizontalUnfilter_SSE2;
+#if defined(CHROMIUM)
+ // TODO(crbug.com/654974)
+ (void)VerticalUnfilter_SSE2;
+#else
WebPUnfilters[WEBP_FILTER_VERTICAL] = VerticalUnfilter_SSE2;
+#endif
WebPUnfilters[WEBP_FILTER_GRADIENT] = GradientUnfilter_SSE2;
WebPFilters[WEBP_FILTER_HORIZONTAL] = HorizontalFilter_SSE2;
diff --git a/thirdparty/libwebp/src/dsp/lossless.c b/thirdparty/libwebp/src/dsp/lossless.c
index aad5f43ec9..d8bbb02b35 100644
--- a/thirdparty/libwebp/src/dsp/lossless.c
+++ b/thirdparty/libwebp/src/dsp/lossless.c
@@ -107,62 +107,62 @@ static WEBP_INLINE uint32_t Select(uint32_t a, uint32_t b, uint32_t c) {
//------------------------------------------------------------------------------
// Predictors
-static uint32_t Predictor0_C(uint32_t left, const uint32_t* const top) {
+uint32_t VP8LPredictor0_C(uint32_t left, const uint32_t* const top) {
(void)top;
(void)left;
return ARGB_BLACK;
}
-static uint32_t Predictor1_C(uint32_t left, const uint32_t* const top) {
+uint32_t VP8LPredictor1_C(uint32_t left, const uint32_t* const top) {
(void)top;
return left;
}
-static uint32_t Predictor2_C(uint32_t left, const uint32_t* const top) {
+uint32_t VP8LPredictor2_C(uint32_t left, const uint32_t* const top) {
(void)left;
return top[0];
}
-static uint32_t Predictor3_C(uint32_t left, const uint32_t* const top) {
+uint32_t VP8LPredictor3_C(uint32_t left, const uint32_t* const top) {
(void)left;
return top[1];
}
-static uint32_t Predictor4_C(uint32_t left, const uint32_t* const top) {
+uint32_t VP8LPredictor4_C(uint32_t left, const uint32_t* const top) {
(void)left;
return top[-1];
}
-static uint32_t Predictor5_C(uint32_t left, const uint32_t* const top) {
+uint32_t VP8LPredictor5_C(uint32_t left, const uint32_t* const top) {
const uint32_t pred = Average3(left, top[0], top[1]);
return pred;
}
-static uint32_t Predictor6_C(uint32_t left, const uint32_t* const top) {
+uint32_t VP8LPredictor6_C(uint32_t left, const uint32_t* const top) {
const uint32_t pred = Average2(left, top[-1]);
return pred;
}
-static uint32_t Predictor7_C(uint32_t left, const uint32_t* const top) {
+uint32_t VP8LPredictor7_C(uint32_t left, const uint32_t* const top) {
const uint32_t pred = Average2(left, top[0]);
return pred;
}
-static uint32_t Predictor8_C(uint32_t left, const uint32_t* const top) {
+uint32_t VP8LPredictor8_C(uint32_t left, const uint32_t* const top) {
const uint32_t pred = Average2(top[-1], top[0]);
(void)left;
return pred;
}
-static uint32_t Predictor9_C(uint32_t left, const uint32_t* const top) {
+uint32_t VP8LPredictor9_C(uint32_t left, const uint32_t* const top) {
const uint32_t pred = Average2(top[0], top[1]);
(void)left;
return pred;
}
-static uint32_t Predictor10_C(uint32_t left, const uint32_t* const top) {
+uint32_t VP8LPredictor10_C(uint32_t left, const uint32_t* const top) {
const uint32_t pred = Average4(left, top[-1], top[0], top[1]);
return pred;
}
-static uint32_t Predictor11_C(uint32_t left, const uint32_t* const top) {
+uint32_t VP8LPredictor11_C(uint32_t left, const uint32_t* const top) {
const uint32_t pred = Select(top[0], left, top[-1]);
return pred;
}
-static uint32_t Predictor12_C(uint32_t left, const uint32_t* const top) {
+uint32_t VP8LPredictor12_C(uint32_t left, const uint32_t* const top) {
const uint32_t pred = ClampedAddSubtractFull(left, top[0], top[-1]);
return pred;
}
-static uint32_t Predictor13_C(uint32_t left, const uint32_t* const top) {
+uint32_t VP8LPredictor13_C(uint32_t left, const uint32_t* const top) {
const uint32_t pred = ClampedAddSubtractHalf(left, top[0], top[-1]);
return pred;
}
@@ -182,18 +182,18 @@ static void PredictorAdd1_C(const uint32_t* in, const uint32_t* upper,
out[i] = left = VP8LAddPixels(in[i], left);
}
}
-GENERATE_PREDICTOR_ADD(Predictor2_C, PredictorAdd2_C)
-GENERATE_PREDICTOR_ADD(Predictor3_C, PredictorAdd3_C)
-GENERATE_PREDICTOR_ADD(Predictor4_C, PredictorAdd4_C)
-GENERATE_PREDICTOR_ADD(Predictor5_C, PredictorAdd5_C)
-GENERATE_PREDICTOR_ADD(Predictor6_C, PredictorAdd6_C)
-GENERATE_PREDICTOR_ADD(Predictor7_C, PredictorAdd7_C)
-GENERATE_PREDICTOR_ADD(Predictor8_C, PredictorAdd8_C)
-GENERATE_PREDICTOR_ADD(Predictor9_C, PredictorAdd9_C)
-GENERATE_PREDICTOR_ADD(Predictor10_C, PredictorAdd10_C)
-GENERATE_PREDICTOR_ADD(Predictor11_C, PredictorAdd11_C)
-GENERATE_PREDICTOR_ADD(Predictor12_C, PredictorAdd12_C)
-GENERATE_PREDICTOR_ADD(Predictor13_C, PredictorAdd13_C)
+GENERATE_PREDICTOR_ADD(VP8LPredictor2_C, PredictorAdd2_C)
+GENERATE_PREDICTOR_ADD(VP8LPredictor3_C, PredictorAdd3_C)
+GENERATE_PREDICTOR_ADD(VP8LPredictor4_C, PredictorAdd4_C)
+GENERATE_PREDICTOR_ADD(VP8LPredictor5_C, PredictorAdd5_C)
+GENERATE_PREDICTOR_ADD(VP8LPredictor6_C, PredictorAdd6_C)
+GENERATE_PREDICTOR_ADD(VP8LPredictor7_C, PredictorAdd7_C)
+GENERATE_PREDICTOR_ADD(VP8LPredictor8_C, PredictorAdd8_C)
+GENERATE_PREDICTOR_ADD(VP8LPredictor9_C, PredictorAdd9_C)
+GENERATE_PREDICTOR_ADD(VP8LPredictor10_C, PredictorAdd10_C)
+GENERATE_PREDICTOR_ADD(VP8LPredictor11_C, PredictorAdd11_C)
+GENERATE_PREDICTOR_ADD(VP8LPredictor12_C, PredictorAdd12_C)
+GENERATE_PREDICTOR_ADD(VP8LPredictor13_C, PredictorAdd13_C)
//------------------------------------------------------------------------------
@@ -562,7 +562,6 @@ VP8LPredictorFunc VP8LPredictors[16];
// exposed plain-C implementations
VP8LPredictorAddSubFunc VP8LPredictorsAdd_C[16];
-VP8LPredictorFunc VP8LPredictors_C[16];
VP8LTransformColorInverseFunc VP8LTransformColorInverse;
@@ -576,6 +575,7 @@ VP8LMapARGBFunc VP8LMapColor32b;
VP8LMapAlphaFunc VP8LMapColor8b;
extern void VP8LDspInitSSE2(void);
+extern void VP8LDspInitSSE41(void);
extern void VP8LDspInitNEON(void);
extern void VP8LDspInitMIPSdspR2(void);
extern void VP8LDspInitMSA(void);
@@ -600,8 +600,7 @@ extern void VP8LDspInitMSA(void);
} while (0);
WEBP_DSP_INIT_FUNC(VP8LDspInit) {
- COPY_PREDICTOR_ARRAY(Predictor, VP8LPredictors)
- COPY_PREDICTOR_ARRAY(Predictor, VP8LPredictors_C)
+ COPY_PREDICTOR_ARRAY(VP8LPredictor, VP8LPredictors)
COPY_PREDICTOR_ARRAY(PredictorAdd, VP8LPredictorsAdd)
COPY_PREDICTOR_ARRAY(PredictorAdd, VP8LPredictorsAdd_C)
@@ -623,9 +622,14 @@ WEBP_DSP_INIT_FUNC(VP8LDspInit) {
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
if (VP8GetCPUInfo != NULL) {
-#if defined(WEBP_USE_SSE2)
+#if defined(WEBP_HAVE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
VP8LDspInitSSE2();
+#if defined(WEBP_HAVE_SSE41)
+ if (VP8GetCPUInfo(kSSE4_1)) {
+ VP8LDspInitSSE41();
+ }
+#endif
}
#endif
#if defined(WEBP_USE_MIPS_DSP_R2)
@@ -640,7 +644,7 @@ WEBP_DSP_INIT_FUNC(VP8LDspInit) {
#endif
}
-#if defined(WEBP_USE_NEON)
+#if defined(WEBP_HAVE_NEON)
if (WEBP_NEON_OMIT_C_CODE ||
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
VP8LDspInitNEON();
diff --git a/thirdparty/libwebp/src/dsp/lossless.h b/thirdparty/libwebp/src/dsp/lossless.h
index f709cc86b2..ebd316d1ed 100644
--- a/thirdparty/libwebp/src/dsp/lossless.h
+++ b/thirdparty/libwebp/src/dsp/lossless.h
@@ -30,7 +30,22 @@ extern "C" {
typedef uint32_t (*VP8LPredictorFunc)(uint32_t left, const uint32_t* const top);
extern VP8LPredictorFunc VP8LPredictors[16];
-extern VP8LPredictorFunc VP8LPredictors_C[16];
+
+uint32_t VP8LPredictor0_C(uint32_t left, const uint32_t* const top);
+uint32_t VP8LPredictor1_C(uint32_t left, const uint32_t* const top);
+uint32_t VP8LPredictor2_C(uint32_t left, const uint32_t* const top);
+uint32_t VP8LPredictor3_C(uint32_t left, const uint32_t* const top);
+uint32_t VP8LPredictor4_C(uint32_t left, const uint32_t* const top);
+uint32_t VP8LPredictor5_C(uint32_t left, const uint32_t* const top);
+uint32_t VP8LPredictor6_C(uint32_t left, const uint32_t* const top);
+uint32_t VP8LPredictor7_C(uint32_t left, const uint32_t* const top);
+uint32_t VP8LPredictor8_C(uint32_t left, const uint32_t* const top);
+uint32_t VP8LPredictor9_C(uint32_t left, const uint32_t* const top);
+uint32_t VP8LPredictor10_C(uint32_t left, const uint32_t* const top);
+uint32_t VP8LPredictor11_C(uint32_t left, const uint32_t* const top);
+uint32_t VP8LPredictor12_C(uint32_t left, const uint32_t* const top);
+uint32_t VP8LPredictor13_C(uint32_t left, const uint32_t* const top);
+
// These Add/Sub function expects upper[-1] and out[-1] to be readable.
typedef void (*VP8LPredictorAddSubFunc)(const uint32_t* in,
const uint32_t* upper, int num_pixels,
diff --git a/thirdparty/libwebp/src/dsp/lossless_common.h b/thirdparty/libwebp/src/dsp/lossless_common.h
index 9c2ebe6809..96a106f9ee 100644
--- a/thirdparty/libwebp/src/dsp/lossless_common.h
+++ b/thirdparty/libwebp/src/dsp/lossless_common.h
@@ -184,19 +184,6 @@ static void PREDICTOR_ADD(const uint32_t* in, const uint32_t* upper, \
} \
}
-// It subtracts the prediction from the input pixel and stores the residual
-// in the output pixel.
-#define GENERATE_PREDICTOR_SUB(PREDICTOR, PREDICTOR_SUB) \
-static void PREDICTOR_SUB(const uint32_t* in, const uint32_t* upper, \
- int num_pixels, uint32_t* out) { \
- int x; \
- assert(upper != NULL); \
- for (x = 0; x < num_pixels; ++x) { \
- const uint32_t pred = (PREDICTOR)(in[x - 1], upper + x); \
- out[x] = VP8LSubPixels(in[x], pred); \
- } \
-}
-
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/thirdparty/libwebp/src/dsp/lossless_enc.c b/thirdparty/libwebp/src/dsp/lossless_enc.c
index 9c36055afc..c3e8537ade 100644
--- a/thirdparty/libwebp/src/dsp/lossless_enc.c
+++ b/thirdparty/libwebp/src/dsp/lossless_enc.c
@@ -329,6 +329,15 @@ const uint8_t kPrefixEncodeExtraBitsValue[PREFIX_LOOKUP_IDX_MAX] = {
static float FastSLog2Slow_C(uint32_t v) {
assert(v >= LOG_LOOKUP_IDX_MAX);
if (v < APPROX_LOG_WITH_CORRECTION_MAX) {
+#if !defined(WEBP_HAVE_SLOW_CLZ_CTZ)
+ // use clz if available
+ const int log_cnt = BitsLog2Floor(v) - 7;
+ const uint32_t y = 1 << log_cnt;
+ int correction = 0;
+ const float v_f = (float)v;
+ const uint32_t orig_v = v;
+ v >>= log_cnt;
+#else
int log_cnt = 0;
uint32_t y = 1;
int correction = 0;
@@ -339,6 +348,7 @@ static float FastSLog2Slow_C(uint32_t v) {
v = v >> 1;
y = y << 1;
} while (v >= LOG_LOOKUP_IDX_MAX);
+#endif
// vf = (2^log_cnt) * Xf; where y = 2^log_cnt and Xf < 256
// Xf = floor(Xf) * (1 + (v % y) / v)
// log2(Xf) = log2(floor(Xf)) + log2(1 + (v % y) / v)
@@ -355,6 +365,14 @@ static float FastSLog2Slow_C(uint32_t v) {
static float FastLog2Slow_C(uint32_t v) {
assert(v >= LOG_LOOKUP_IDX_MAX);
if (v < APPROX_LOG_WITH_CORRECTION_MAX) {
+#if !defined(WEBP_HAVE_SLOW_CLZ_CTZ)
+ // use clz if available
+ const int log_cnt = BitsLog2Floor(v) - 7;
+ const uint32_t y = 1 << log_cnt;
+ const uint32_t orig_v = v;
+ double log_2;
+ v >>= log_cnt;
+#else
int log_cnt = 0;
uint32_t y = 1;
const uint32_t orig_v = v;
@@ -364,6 +382,7 @@ static float FastLog2Slow_C(uint32_t v) {
v = v >> 1;
y = y << 1;
} while (v >= LOG_LOOKUP_IDX_MAX);
+#endif
log_2 = kLog2Table[v] + log_cnt;
if (orig_v >= APPROX_LOG_MAX) {
// Since the division is still expensive, add this correction factor only
@@ -702,140 +721,6 @@ void VP8LHistogramAdd(const VP8LHistogram* const a,
//------------------------------------------------------------------------------
// Image transforms.
-static WEBP_INLINE uint32_t Average2(uint32_t a0, uint32_t a1) {
- return (((a0 ^ a1) & 0xfefefefeu) >> 1) + (a0 & a1);
-}
-
-static WEBP_INLINE uint32_t Average3(uint32_t a0, uint32_t a1, uint32_t a2) {
- return Average2(Average2(a0, a2), a1);
-}
-
-static WEBP_INLINE uint32_t Average4(uint32_t a0, uint32_t a1,
- uint32_t a2, uint32_t a3) {
- return Average2(Average2(a0, a1), Average2(a2, a3));
-}
-
-static WEBP_INLINE uint32_t Clip255(uint32_t a) {
- if (a < 256) {
- return a;
- }
- // return 0, when a is a negative integer.
- // return 255, when a is positive.
- return ~a >> 24;
-}
-
-static WEBP_INLINE int AddSubtractComponentFull(int a, int b, int c) {
- return Clip255(a + b - c);
-}
-
-static WEBP_INLINE uint32_t ClampedAddSubtractFull(uint32_t c0, uint32_t c1,
- uint32_t c2) {
- const int a = AddSubtractComponentFull(c0 >> 24, c1 >> 24, c2 >> 24);
- const int r = AddSubtractComponentFull((c0 >> 16) & 0xff,
- (c1 >> 16) & 0xff,
- (c2 >> 16) & 0xff);
- const int g = AddSubtractComponentFull((c0 >> 8) & 0xff,
- (c1 >> 8) & 0xff,
- (c2 >> 8) & 0xff);
- const int b = AddSubtractComponentFull(c0 & 0xff, c1 & 0xff, c2 & 0xff);
- return ((uint32_t)a << 24) | (r << 16) | (g << 8) | b;
-}
-
-static WEBP_INLINE int AddSubtractComponentHalf(int a, int b) {
- return Clip255(a + (a - b) / 2);
-}
-
-static WEBP_INLINE uint32_t ClampedAddSubtractHalf(uint32_t c0, uint32_t c1,
- uint32_t c2) {
- const uint32_t ave = Average2(c0, c1);
- const int a = AddSubtractComponentHalf(ave >> 24, c2 >> 24);
- const int r = AddSubtractComponentHalf((ave >> 16) & 0xff, (c2 >> 16) & 0xff);
- const int g = AddSubtractComponentHalf((ave >> 8) & 0xff, (c2 >> 8) & 0xff);
- const int b = AddSubtractComponentHalf((ave >> 0) & 0xff, (c2 >> 0) & 0xff);
- return ((uint32_t)a << 24) | (r << 16) | (g << 8) | b;
-}
-
-// gcc-4.9 on ARM generates incorrect code in Select() when Sub3() is inlined.
-#if defined(__arm__) && \
- (LOCAL_GCC_VERSION == 0x409 || LOCAL_GCC_VERSION == 0x408)
-# define LOCAL_INLINE __attribute__ ((noinline))
-#else
-# define LOCAL_INLINE WEBP_INLINE
-#endif
-
-static LOCAL_INLINE int Sub3(int a, int b, int c) {
- const int pb = b - c;
- const int pa = a - c;
- return abs(pb) - abs(pa);
-}
-
-#undef LOCAL_INLINE
-
-static WEBP_INLINE uint32_t Select(uint32_t a, uint32_t b, uint32_t c) {
- const int pa_minus_pb =
- Sub3((a >> 24) , (b >> 24) , (c >> 24) ) +
- Sub3((a >> 16) & 0xff, (b >> 16) & 0xff, (c >> 16) & 0xff) +
- Sub3((a >> 8) & 0xff, (b >> 8) & 0xff, (c >> 8) & 0xff) +
- Sub3((a ) & 0xff, (b ) & 0xff, (c ) & 0xff);
- return (pa_minus_pb <= 0) ? a : b;
-}
-
-//------------------------------------------------------------------------------
-// Predictors
-
-static uint32_t Predictor2(uint32_t left, const uint32_t* const top) {
- (void)left;
- return top[0];
-}
-static uint32_t Predictor3(uint32_t left, const uint32_t* const top) {
- (void)left;
- return top[1];
-}
-static uint32_t Predictor4(uint32_t left, const uint32_t* const top) {
- (void)left;
- return top[-1];
-}
-static uint32_t Predictor5(uint32_t left, const uint32_t* const top) {
- const uint32_t pred = Average3(left, top[0], top[1]);
- return pred;
-}
-static uint32_t Predictor6(uint32_t left, const uint32_t* const top) {
- const uint32_t pred = Average2(left, top[-1]);
- return pred;
-}
-static uint32_t Predictor7(uint32_t left, const uint32_t* const top) {
- const uint32_t pred = Average2(left, top[0]);
- return pred;
-}
-static uint32_t Predictor8(uint32_t left, const uint32_t* const top) {
- const uint32_t pred = Average2(top[-1], top[0]);
- (void)left;
- return pred;
-}
-static uint32_t Predictor9(uint32_t left, const uint32_t* const top) {
- const uint32_t pred = Average2(top[0], top[1]);
- (void)left;
- return pred;
-}
-static uint32_t Predictor10(uint32_t left, const uint32_t* const top) {
- const uint32_t pred = Average4(left, top[-1], top[0], top[1]);
- return pred;
-}
-static uint32_t Predictor11(uint32_t left, const uint32_t* const top) {
- const uint32_t pred = Select(top[0], left, top[-1]);
- return pred;
-}
-static uint32_t Predictor12(uint32_t left, const uint32_t* const top) {
- const uint32_t pred = ClampedAddSubtractFull(left, top[0], top[-1]);
- return pred;
-}
-static uint32_t Predictor13(uint32_t left, const uint32_t* const top) {
- const uint32_t pred = ClampedAddSubtractHalf(left, top[0], top[-1]);
- return pred;
-}
-
-//------------------------------------------------------------------------------
-
static void PredictorSub0_C(const uint32_t* in, const uint32_t* upper,
int num_pixels, uint32_t* out) {
int i;
@@ -850,18 +735,33 @@ static void PredictorSub1_C(const uint32_t* in, const uint32_t* upper,
(void)upper;
}
-GENERATE_PREDICTOR_SUB(Predictor2, PredictorSub2_C)
-GENERATE_PREDICTOR_SUB(Predictor3, PredictorSub3_C)
-GENERATE_PREDICTOR_SUB(Predictor4, PredictorSub4_C)
-GENERATE_PREDICTOR_SUB(Predictor5, PredictorSub5_C)
-GENERATE_PREDICTOR_SUB(Predictor6, PredictorSub6_C)
-GENERATE_PREDICTOR_SUB(Predictor7, PredictorSub7_C)
-GENERATE_PREDICTOR_SUB(Predictor8, PredictorSub8_C)
-GENERATE_PREDICTOR_SUB(Predictor9, PredictorSub9_C)
-GENERATE_PREDICTOR_SUB(Predictor10, PredictorSub10_C)
-GENERATE_PREDICTOR_SUB(Predictor11, PredictorSub11_C)
-GENERATE_PREDICTOR_SUB(Predictor12, PredictorSub12_C)
-GENERATE_PREDICTOR_SUB(Predictor13, PredictorSub13_C)
+// It subtracts the prediction from the input pixel and stores the residual
+// in the output pixel.
+#define GENERATE_PREDICTOR_SUB(PREDICTOR_I) \
+static void PredictorSub##PREDICTOR_I##_C(const uint32_t* in, \
+ const uint32_t* upper, \
+ int num_pixels, uint32_t* out) { \
+ int x; \
+ assert(upper != NULL); \
+ for (x = 0; x < num_pixels; ++x) { \
+ const uint32_t pred = \
+ VP8LPredictor##PREDICTOR_I##_C(in[x - 1], upper + x); \
+ out[x] = VP8LSubPixels(in[x], pred); \
+ } \
+}
+
+GENERATE_PREDICTOR_SUB(2)
+GENERATE_PREDICTOR_SUB(3)
+GENERATE_PREDICTOR_SUB(4)
+GENERATE_PREDICTOR_SUB(5)
+GENERATE_PREDICTOR_SUB(6)
+GENERATE_PREDICTOR_SUB(7)
+GENERATE_PREDICTOR_SUB(8)
+GENERATE_PREDICTOR_SUB(9)
+GENERATE_PREDICTOR_SUB(10)
+GENERATE_PREDICTOR_SUB(11)
+GENERATE_PREDICTOR_SUB(12)
+GENERATE_PREDICTOR_SUB(13)
//------------------------------------------------------------------------------
@@ -962,10 +862,10 @@ WEBP_DSP_INIT_FUNC(VP8LEncDspInit) {
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
if (VP8GetCPUInfo != NULL) {
-#if defined(WEBP_USE_SSE2)
+#if defined(WEBP_HAVE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
VP8LEncDspInitSSE2();
-#if defined(WEBP_USE_SSE41)
+#if defined(WEBP_HAVE_SSE41)
if (VP8GetCPUInfo(kSSE4_1)) {
VP8LEncDspInitSSE41();
}
@@ -989,7 +889,7 @@ WEBP_DSP_INIT_FUNC(VP8LEncDspInit) {
#endif
}
-#if defined(WEBP_USE_NEON)
+#if defined(WEBP_HAVE_NEON)
if (WEBP_NEON_OMIT_C_CODE ||
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
VP8LEncDspInitNEON();
diff --git a/thirdparty/libwebp/src/dsp/lossless_enc_sse2.c b/thirdparty/libwebp/src/dsp/lossless_enc_sse2.c
index e676f6fdc9..b2f83b871c 100644
--- a/thirdparty/libwebp/src/dsp/lossless_enc_sse2.c
+++ b/thirdparty/libwebp/src/dsp/lossless_enc_sse2.c
@@ -232,76 +232,55 @@ static void AddVectorEq_SSE2(const uint32_t* a, uint32_t* out, int size) {
//------------------------------------------------------------------------------
// Entropy
-// Checks whether the X or Y contribution is worth computing and adding.
-// Used in loop unrolling.
-#define ANALYZE_X_OR_Y(x_or_y, j) \
- do { \
- if ((x_or_y)[i + (j)] != 0) retval -= VP8LFastSLog2((x_or_y)[i + (j)]); \
- } while (0)
-
-// Checks whether the X + Y contribution is worth computing and adding.
-// Used in loop unrolling.
-#define ANALYZE_XY(j) \
- do { \
- if (tmp[j] != 0) { \
- retval -= VP8LFastSLog2(tmp[j]); \
- ANALYZE_X_OR_Y(X, j); \
- } \
- } while (0)
+// TODO(https://crbug.com/webp/499): this function produces different results
+// from the C code due to use of double/float resulting in output differences
+// when compared to -noasm.
+#if !(defined(WEBP_HAVE_SLOW_CLZ_CTZ) || defined(__i386__) || defined(_M_IX86))
static float CombinedShannonEntropy_SSE2(const int X[256], const int Y[256]) {
int i;
double retval = 0.;
- int sumX, sumXY;
- int32_t tmp[4];
- __m128i zero = _mm_setzero_si128();
- // Sums up X + Y, 4 ints at a time (and will merge it at the end for sumXY).
- __m128i sumXY_128 = zero;
- __m128i sumX_128 = zero;
-
- for (i = 0; i < 256; i += 4) {
- const __m128i x = _mm_loadu_si128((const __m128i*)(X + i));
- const __m128i y = _mm_loadu_si128((const __m128i*)(Y + i));
-
- // Check if any X is non-zero: this actually provides a speedup as X is
- // usually sparse.
- if (_mm_movemask_epi8(_mm_cmpeq_epi32(x, zero)) != 0xFFFF) {
- const __m128i xy_128 = _mm_add_epi32(x, y);
- sumXY_128 = _mm_add_epi32(sumXY_128, xy_128);
-
- sumX_128 = _mm_add_epi32(sumX_128, x);
-
- // Analyze the different X + Y.
- _mm_storeu_si128((__m128i*)tmp, xy_128);
-
- ANALYZE_XY(0);
- ANALYZE_XY(1);
- ANALYZE_XY(2);
- ANALYZE_XY(3);
- } else {
- // X is fully 0, so only deal with Y.
- sumXY_128 = _mm_add_epi32(sumXY_128, y);
-
- ANALYZE_X_OR_Y(Y, 0);
- ANALYZE_X_OR_Y(Y, 1);
- ANALYZE_X_OR_Y(Y, 2);
- ANALYZE_X_OR_Y(Y, 3);
+ int sumX = 0, sumXY = 0;
+ const __m128i zero = _mm_setzero_si128();
+
+ for (i = 0; i < 256; i += 16) {
+ const __m128i x0 = _mm_loadu_si128((const __m128i*)(X + i + 0));
+ const __m128i y0 = _mm_loadu_si128((const __m128i*)(Y + i + 0));
+ const __m128i x1 = _mm_loadu_si128((const __m128i*)(X + i + 4));
+ const __m128i y1 = _mm_loadu_si128((const __m128i*)(Y + i + 4));
+ const __m128i x2 = _mm_loadu_si128((const __m128i*)(X + i + 8));
+ const __m128i y2 = _mm_loadu_si128((const __m128i*)(Y + i + 8));
+ const __m128i x3 = _mm_loadu_si128((const __m128i*)(X + i + 12));
+ const __m128i y3 = _mm_loadu_si128((const __m128i*)(Y + i + 12));
+ const __m128i x4 = _mm_packs_epi16(_mm_packs_epi32(x0, x1),
+ _mm_packs_epi32(x2, x3));
+ const __m128i y4 = _mm_packs_epi16(_mm_packs_epi32(y0, y1),
+ _mm_packs_epi32(y2, y3));
+ const int32_t mx = _mm_movemask_epi8(_mm_cmpgt_epi8(x4, zero));
+ int32_t my = _mm_movemask_epi8(_mm_cmpgt_epi8(y4, zero)) | mx;
+ while (my) {
+ const int32_t j = BitsCtz(my);
+ int xy;
+ if ((mx >> j) & 1) {
+ const int x = X[i + j];
+ sumXY += x;
+ retval -= VP8LFastSLog2(x);
+ }
+ xy = X[i + j] + Y[i + j];
+ sumX += xy;
+ retval -= VP8LFastSLog2(xy);
+ my &= my - 1;
}
}
-
- // Sum up sumX_128 to get sumX.
- _mm_storeu_si128((__m128i*)tmp, sumX_128);
- sumX = tmp[3] + tmp[2] + tmp[1] + tmp[0];
-
- // Sum up sumXY_128 to get sumXY.
- _mm_storeu_si128((__m128i*)tmp, sumXY_128);
- sumXY = tmp[3] + tmp[2] + tmp[1] + tmp[0];
-
retval += VP8LFastSLog2(sumX) + VP8LFastSLog2(sumXY);
return (float)retval;
}
-#undef ANALYZE_X_OR_Y
-#undef ANALYZE_XY
+
+#else
+
+#define DONT_USE_COMBINED_SHANNON_ENTROPY_SSE2_FUNC // won't be faster
+
+#endif
//------------------------------------------------------------------------------
@@ -460,20 +439,22 @@ static void PredictorSub0_SSE2(const uint32_t* in, const uint32_t* upper,
(void)upper;
}
-#define GENERATE_PREDICTOR_1(X, IN) \
-static void PredictorSub##X##_SSE2(const uint32_t* in, const uint32_t* upper, \
- int num_pixels, uint32_t* out) { \
- int i; \
- for (i = 0; i + 4 <= num_pixels; i += 4) { \
- const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); \
- const __m128i pred = _mm_loadu_si128((const __m128i*)&(IN)); \
- const __m128i res = _mm_sub_epi8(src, pred); \
- _mm_storeu_si128((__m128i*)&out[i], res); \
- } \
- if (i != num_pixels) { \
- VP8LPredictorsSub_C[(X)](in + i, upper + i, num_pixels - i, out + i); \
- } \
-}
+#define GENERATE_PREDICTOR_1(X, IN) \
+ static void PredictorSub##X##_SSE2(const uint32_t* const in, \
+ const uint32_t* const upper, \
+ int num_pixels, uint32_t* const out) { \
+ int i; \
+ for (i = 0; i + 4 <= num_pixels; i += 4) { \
+ const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); \
+ const __m128i pred = _mm_loadu_si128((const __m128i*)&(IN)); \
+ const __m128i res = _mm_sub_epi8(src, pred); \
+ _mm_storeu_si128((__m128i*)&out[i], res); \
+ } \
+ if (i != num_pixels) { \
+ VP8LPredictorsSub_C[(X)](in + i, WEBP_OFFSET_PTR(upper, i), \
+ num_pixels - i, out + i); \
+ } \
+ }
GENERATE_PREDICTOR_1(1, in[i - 1]) // Predictor1: L
GENERATE_PREDICTOR_1(2, upper[i]) // Predictor2: T
@@ -657,7 +638,9 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInitSSE2(void) {
VP8LCollectColorRedTransforms = CollectColorRedTransforms_SSE2;
VP8LAddVector = AddVector_SSE2;
VP8LAddVectorEq = AddVectorEq_SSE2;
+#if !defined(DONT_USE_COMBINED_SHANNON_ENTROPY_SSE2_FUNC)
VP8LCombinedShannonEntropy = CombinedShannonEntropy_SSE2;
+#endif
VP8LVectorMismatch = VectorMismatch_SSE2;
VP8LBundleColorMap = BundleColorMap_SSE2;
diff --git a/thirdparty/libwebp/src/dsp/lossless_enc_sse41.c b/thirdparty/libwebp/src/dsp/lossless_enc_sse41.c
index 719d8ed25e..ad358a6f25 100644
--- a/thirdparty/libwebp/src/dsp/lossless_enc_sse41.c
+++ b/thirdparty/libwebp/src/dsp/lossless_enc_sse41.c
@@ -44,46 +44,47 @@ static void SubtractGreenFromBlueAndRed_SSE41(uint32_t* argb_data,
//------------------------------------------------------------------------------
// Color Transform
-#define SPAN 8
+#define MK_CST_16(HI, LO) \
+ _mm_set1_epi32((int)(((uint32_t)(HI) << 16) | ((LO) & 0xffff)))
+
static void CollectColorBlueTransforms_SSE41(const uint32_t* argb, int stride,
int tile_width, int tile_height,
int green_to_blue, int red_to_blue,
int histo[]) {
- const __m128i mults_r = _mm_set1_epi16(CST_5b(red_to_blue));
- const __m128i mults_g = _mm_set1_epi16(CST_5b(green_to_blue));
- const __m128i mask_g = _mm_set1_epi16((short)0xff00); // green mask
- const __m128i mask_gb = _mm_set1_epi32(0xffff); // green/blue mask
- const __m128i mask_b = _mm_set1_epi16(0x00ff); // blue mask
- const __m128i shuffler_lo = _mm_setr_epi8(-1, 2, -1, 6, -1, 10, -1, 14, -1,
- -1, -1, -1, -1, -1, -1, -1);
- const __m128i shuffler_hi = _mm_setr_epi8(-1, -1, -1, -1, -1, -1, -1, -1, -1,
- 2, -1, 6, -1, 10, -1, 14);
- int y;
- for (y = 0; y < tile_height; ++y) {
- const uint32_t* const src = argb + y * stride;
- int i, x;
- for (x = 0; x + SPAN <= tile_width; x += SPAN) {
- uint16_t values[SPAN];
- const __m128i in0 = _mm_loadu_si128((__m128i*)&src[x + 0]);
- const __m128i in1 = _mm_loadu_si128((__m128i*)&src[x + SPAN / 2]);
- const __m128i r0 = _mm_shuffle_epi8(in0, shuffler_lo);
- const __m128i r1 = _mm_shuffle_epi8(in1, shuffler_hi);
- const __m128i r = _mm_or_si128(r0, r1); // r 0
- const __m128i gb0 = _mm_and_si128(in0, mask_gb);
- const __m128i gb1 = _mm_and_si128(in1, mask_gb);
- const __m128i gb = _mm_packus_epi32(gb0, gb1); // g b
- const __m128i g = _mm_and_si128(gb, mask_g); // g 0
- const __m128i A = _mm_mulhi_epi16(r, mults_r); // x dbr
- const __m128i B = _mm_mulhi_epi16(g, mults_g); // x dbg
- const __m128i C = _mm_sub_epi8(gb, B); // x b'
- const __m128i D = _mm_sub_epi8(C, A); // x b''
- const __m128i E = _mm_and_si128(D, mask_b); // 0 b''
- _mm_storeu_si128((__m128i*)values, E);
- for (i = 0; i < SPAN; ++i) ++histo[values[i]];
+ const __m128i mult =
+ MK_CST_16(CST_5b(red_to_blue) + 256,CST_5b(green_to_blue));
+ const __m128i perm =
+ _mm_setr_epi8(-1, 1, -1, 2, -1, 5, -1, 6, -1, 9, -1, 10, -1, 13, -1, 14);
+ if (tile_width >= 4) {
+ int y;
+ for (y = 0; y < tile_height; ++y) {
+ const uint32_t* const src = argb + y * stride;
+ const __m128i A1 = _mm_loadu_si128((const __m128i*)src);
+ const __m128i B1 = _mm_shuffle_epi8(A1, perm);
+ const __m128i C1 = _mm_mulhi_epi16(B1, mult);
+ const __m128i D1 = _mm_sub_epi16(A1, C1);
+ __m128i E = _mm_add_epi16(_mm_srli_epi32(D1, 16), D1);
+ int x;
+ for (x = 4; x + 4 <= tile_width; x += 4) {
+ const __m128i A2 = _mm_loadu_si128((const __m128i*)(src + x));
+ __m128i B2, C2, D2;
+ ++histo[_mm_extract_epi8(E, 0)];
+ B2 = _mm_shuffle_epi8(A2, perm);
+ ++histo[_mm_extract_epi8(E, 4)];
+ C2 = _mm_mulhi_epi16(B2, mult);
+ ++histo[_mm_extract_epi8(E, 8)];
+ D2 = _mm_sub_epi16(A2, C2);
+ ++histo[_mm_extract_epi8(E, 12)];
+ E = _mm_add_epi16(_mm_srli_epi32(D2, 16), D2);
+ }
+ ++histo[_mm_extract_epi8(E, 0)];
+ ++histo[_mm_extract_epi8(E, 4)];
+ ++histo[_mm_extract_epi8(E, 8)];
+ ++histo[_mm_extract_epi8(E, 12)];
}
}
{
- const int left_over = tile_width & (SPAN - 1);
+ const int left_over = tile_width & 3;
if (left_over > 0) {
VP8LCollectColorBlueTransforms_C(argb + tile_width - left_over, stride,
left_over, tile_height,
@@ -95,33 +96,37 @@ static void CollectColorBlueTransforms_SSE41(const uint32_t* argb, int stride,
static void CollectColorRedTransforms_SSE41(const uint32_t* argb, int stride,
int tile_width, int tile_height,
int green_to_red, int histo[]) {
- const __m128i mults_g = _mm_set1_epi16(CST_5b(green_to_red));
- const __m128i mask_g = _mm_set1_epi32(0x00ff00); // green mask
- const __m128i mask = _mm_set1_epi16(0xff);
-
- int y;
- for (y = 0; y < tile_height; ++y) {
- const uint32_t* const src = argb + y * stride;
- int i, x;
- for (x = 0; x + SPAN <= tile_width; x += SPAN) {
- uint16_t values[SPAN];
- const __m128i in0 = _mm_loadu_si128((__m128i*)&src[x + 0]);
- const __m128i in1 = _mm_loadu_si128((__m128i*)&src[x + SPAN / 2]);
- const __m128i g0 = _mm_and_si128(in0, mask_g); // 0 0 | g 0
- const __m128i g1 = _mm_and_si128(in1, mask_g);
- const __m128i g = _mm_packus_epi32(g0, g1); // g 0
- const __m128i A0 = _mm_srli_epi32(in0, 16); // 0 0 | x r
- const __m128i A1 = _mm_srli_epi32(in1, 16);
- const __m128i A = _mm_packus_epi32(A0, A1); // x r
- const __m128i B = _mm_mulhi_epi16(g, mults_g); // x dr
- const __m128i C = _mm_sub_epi8(A, B); // x r'
- const __m128i D = _mm_and_si128(C, mask); // 0 r'
- _mm_storeu_si128((__m128i*)values, D);
- for (i = 0; i < SPAN; ++i) ++histo[values[i]];
+
+ const __m128i mult = MK_CST_16(0, CST_5b(green_to_red));
+ const __m128i mask_g = _mm_set1_epi32(0x0000ff00);
+ if (tile_width >= 4) {
+ int y;
+ for (y = 0; y < tile_height; ++y) {
+ const uint32_t* const src = argb + y * stride;
+ const __m128i A1 = _mm_loadu_si128((const __m128i*)src);
+ const __m128i B1 = _mm_and_si128(A1, mask_g);
+ const __m128i C1 = _mm_madd_epi16(B1, mult);
+ __m128i D = _mm_sub_epi16(A1, C1);
+ int x;
+ for (x = 4; x + 4 <= tile_width; x += 4) {
+ const __m128i A2 = _mm_loadu_si128((const __m128i*)(src + x));
+ __m128i B2, C2;
+ ++histo[_mm_extract_epi8(D, 2)];
+ B2 = _mm_and_si128(A2, mask_g);
+ ++histo[_mm_extract_epi8(D, 6)];
+ C2 = _mm_madd_epi16(B2, mult);
+ ++histo[_mm_extract_epi8(D, 10)];
+ ++histo[_mm_extract_epi8(D, 14)];
+ D = _mm_sub_epi16(A2, C2);
+ }
+ ++histo[_mm_extract_epi8(D, 2)];
+ ++histo[_mm_extract_epi8(D, 6)];
+ ++histo[_mm_extract_epi8(D, 10)];
+ ++histo[_mm_extract_epi8(D, 14)];
}
}
{
- const int left_over = tile_width & (SPAN - 1);
+ const int left_over = tile_width & 3;
if (left_over > 0) {
VP8LCollectColorRedTransforms_C(argb + tile_width - left_over, stride,
left_over, tile_height, green_to_red,
@@ -130,6 +135,8 @@ static void CollectColorRedTransforms_SSE41(const uint32_t* argb, int stride,
}
}
+#undef MK_CST_16
+
//------------------------------------------------------------------------------
// Entry point
diff --git a/thirdparty/libwebp/src/dsp/lossless_sse2.c b/thirdparty/libwebp/src/dsp/lossless_sse2.c
index aef0cee1b3..3a0eb440db 100644
--- a/thirdparty/libwebp/src/dsp/lossless_sse2.c
+++ b/thirdparty/libwebp/src/dsp/lossless_sse2.c
@@ -18,7 +18,6 @@
#include "src/dsp/common_sse2.h"
#include "src/dsp/lossless.h"
#include "src/dsp/lossless_common.h"
-#include <assert.h>
#include <emmintrin.h>
//------------------------------------------------------------------------------
diff --git a/thirdparty/libwebp/src/dsp/lossless_sse41.c b/thirdparty/libwebp/src/dsp/lossless_sse41.c
new file mode 100644
index 0000000000..b0d6daa7fe
--- /dev/null
+++ b/thirdparty/libwebp/src/dsp/lossless_sse41.c
@@ -0,0 +1,132 @@
+// Copyright 2021 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// SSE41 variant of methods for lossless decoder
+
+#include "src/dsp/dsp.h"
+
+#if defined(WEBP_USE_SSE41)
+
+#include "src/dsp/common_sse41.h"
+#include "src/dsp/lossless.h"
+#include "src/dsp/lossless_common.h"
+
+//------------------------------------------------------------------------------
+// Color-space conversion functions
+
+static void TransformColorInverse_SSE41(const VP8LMultipliers* const m,
+ const uint32_t* const src,
+ int num_pixels, uint32_t* dst) {
+// sign-extended multiplying constants, pre-shifted by 5.
+#define CST(X) (((int16_t)(m->X << 8)) >> 5) // sign-extend
+ const __m128i mults_rb = _mm_set1_epi32((uint32_t)CST(green_to_red_) << 16 |
+ (CST(green_to_blue_) & 0xffff));
+ const __m128i mults_b2 = _mm_set1_epi32(CST(red_to_blue_));
+#undef CST
+ const __m128i mask_ag = _mm_set1_epi32(0xff00ff00);
+ const __m128i perm1 = _mm_setr_epi8(-1, 1, -1, 1, -1, 5, -1, 5,
+ -1, 9, -1, 9, -1, 13, -1, 13);
+ const __m128i perm2 = _mm_setr_epi8(-1, 2, -1, -1, -1, 6, -1, -1,
+ -1, 10, -1, -1, -1, 14, -1, -1);
+ int i;
+ for (i = 0; i + 4 <= num_pixels; i += 4) {
+ const __m128i A = _mm_loadu_si128((const __m128i*)(src + i));
+ const __m128i B = _mm_shuffle_epi8(A, perm1); // argb -> g0g0
+ const __m128i C = _mm_mulhi_epi16(B, mults_rb);
+ const __m128i D = _mm_add_epi8(A, C);
+ const __m128i E = _mm_shuffle_epi8(D, perm2);
+ const __m128i F = _mm_mulhi_epi16(E, mults_b2);
+ const __m128i G = _mm_add_epi8(D, F);
+ const __m128i out = _mm_blendv_epi8(G, A, mask_ag);
+ _mm_storeu_si128((__m128i*)&dst[i], out);
+ }
+ // Fall-back to C-version for left-overs.
+ if (i != num_pixels) {
+ VP8LTransformColorInverse_C(m, src + i, num_pixels - i, dst + i);
+ }
+}
+
+//------------------------------------------------------------------------------
+
+#define ARGB_TO_RGB_SSE41 do { \
+ while (num_pixels >= 16) { \
+ const __m128i in0 = _mm_loadu_si128(in + 0); \
+ const __m128i in1 = _mm_loadu_si128(in + 1); \
+ const __m128i in2 = _mm_loadu_si128(in + 2); \
+ const __m128i in3 = _mm_loadu_si128(in + 3); \
+ const __m128i a0 = _mm_shuffle_epi8(in0, perm0); \
+ const __m128i a1 = _mm_shuffle_epi8(in1, perm1); \
+ const __m128i a2 = _mm_shuffle_epi8(in2, perm2); \
+ const __m128i a3 = _mm_shuffle_epi8(in3, perm3); \
+ const __m128i b0 = _mm_blend_epi16(a0, a1, 0xc0); \
+ const __m128i b1 = _mm_blend_epi16(a1, a2, 0xf0); \
+ const __m128i b2 = _mm_blend_epi16(a2, a3, 0xfc); \
+ _mm_storeu_si128(out + 0, b0); \
+ _mm_storeu_si128(out + 1, b1); \
+ _mm_storeu_si128(out + 2, b2); \
+ in += 4; \
+ out += 3; \
+ num_pixels -= 16; \
+ } \
+} while (0)
+
+static void ConvertBGRAToRGB_SSE41(const uint32_t* src, int num_pixels,
+ uint8_t* dst) {
+ const __m128i* in = (const __m128i*)src;
+ __m128i* out = (__m128i*)dst;
+ const __m128i perm0 = _mm_setr_epi8(2, 1, 0, 6, 5, 4, 10, 9,
+ 8, 14, 13, 12, -1, -1, -1, -1);
+ const __m128i perm1 = _mm_shuffle_epi32(perm0, 0x39);
+ const __m128i perm2 = _mm_shuffle_epi32(perm0, 0x4e);
+ const __m128i perm3 = _mm_shuffle_epi32(perm0, 0x93);
+
+ ARGB_TO_RGB_SSE41;
+
+ // left-overs
+ if (num_pixels > 0) {
+ VP8LConvertBGRAToRGB_C((const uint32_t*)in, num_pixels, (uint8_t*)out);
+ }
+}
+
+static void ConvertBGRAToBGR_SSE41(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
+ const __m128i* in = (const __m128i*)src;
+ __m128i* out = (__m128i*)dst;
+ const __m128i perm0 = _mm_setr_epi8(0, 1, 2, 4, 5, 6, 8, 9, 10,
+ 12, 13, 14, -1, -1, -1, -1);
+ const __m128i perm1 = _mm_shuffle_epi32(perm0, 0x39);
+ const __m128i perm2 = _mm_shuffle_epi32(perm0, 0x4e);
+ const __m128i perm3 = _mm_shuffle_epi32(perm0, 0x93);
+
+ ARGB_TO_RGB_SSE41;
+
+ // left-overs
+ if (num_pixels > 0) {
+ VP8LConvertBGRAToBGR_C((const uint32_t*)in, num_pixels, (uint8_t*)out);
+ }
+}
+
+#undef ARGB_TO_RGB_SSE41
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void VP8LDspInitSSE41(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInitSSE41(void) {
+ VP8LTransformColorInverse = TransformColorInverse_SSE41;
+ VP8LConvertBGRAToRGB = ConvertBGRAToRGB_SSE41;
+ VP8LConvertBGRAToBGR = ConvertBGRAToBGR_SSE41;
+}
+
+#else // !WEBP_USE_SSE41
+
+WEBP_DSP_INIT_STUB(VP8LDspInitSSE41)
+
+#endif // WEBP_USE_SSE41
diff --git a/thirdparty/libwebp/src/dsp/rescaler.c b/thirdparty/libwebp/src/dsp/rescaler.c
index c5a01e82df..14620ce4f1 100644
--- a/thirdparty/libwebp/src/dsp/rescaler.c
+++ b/thirdparty/libwebp/src/dsp/rescaler.c
@@ -38,8 +38,9 @@ void WebPRescalerImportRowExpand_C(WebPRescaler* const wrk,
int x_out = channel;
// simple bilinear interpolation
int accum = wrk->x_add;
- int left = src[x_in];
- int right = (wrk->src_width > 1) ? src[x_in + x_stride] : left;
+ rescaler_t left = (rescaler_t)src[x_in];
+ rescaler_t right =
+ (wrk->src_width > 1) ? (rescaler_t)src[x_in + x_stride] : left;
x_in += x_stride;
while (1) {
wrk->frow[x_out] = right * wrk->x_add + (left - right) * accum;
@@ -50,7 +51,7 @@ void WebPRescalerImportRowExpand_C(WebPRescaler* const wrk,
left = right;
x_in += x_stride;
assert(x_in < wrk->src_width * x_stride);
- right = src[x_in];
+ right = (rescaler_t)src[x_in];
accum += wrk->x_add;
}
}
@@ -213,7 +214,7 @@ WEBP_DSP_INIT_FUNC(WebPRescalerDspInit) {
WebPRescalerImportRowShrink = WebPRescalerImportRowShrink_C;
if (VP8GetCPUInfo != NULL) {
-#if defined(WEBP_USE_SSE2)
+#if defined(WEBP_HAVE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
WebPRescalerDspInitSSE2();
}
@@ -235,7 +236,7 @@ WEBP_DSP_INIT_FUNC(WebPRescalerDspInit) {
#endif
}
-#if defined(WEBP_USE_NEON)
+#if defined(WEBP_HAVE_NEON)
if (WEBP_NEON_OMIT_C_CODE ||
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
WebPRescalerDspInitNEON();
diff --git a/thirdparty/libwebp/src/dsp/ssim.c b/thirdparty/libwebp/src/dsp/ssim.c
index 989ce8254c..f85c2e6e5b 100644
--- a/thirdparty/libwebp/src/dsp/ssim.c
+++ b/thirdparty/libwebp/src/dsp/ssim.c
@@ -150,7 +150,7 @@ WEBP_DSP_INIT_FUNC(VP8SSIMDspInit) {
#endif
if (VP8GetCPUInfo != NULL) {
-#if defined(WEBP_USE_SSE2)
+#if defined(WEBP_HAVE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
VP8SSIMDspInitSSE2();
}
diff --git a/thirdparty/libwebp/src/dsp/upsampling.c b/thirdparty/libwebp/src/dsp/upsampling.c
index 9b60da5bbb..87f771f3eb 100644
--- a/thirdparty/libwebp/src/dsp/upsampling.c
+++ b/thirdparty/libwebp/src/dsp/upsampling.c
@@ -233,12 +233,12 @@ WEBP_DSP_INIT_FUNC(WebPInitYUV444Converters) {
WebPYUV444Converters[MODE_rgbA_4444] = WebPYuv444ToRgba4444_C;
if (VP8GetCPUInfo != NULL) {
-#if defined(WEBP_USE_SSE2)
+#if defined(WEBP_HAVE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
WebPInitYUV444ConvertersSSE2();
}
#endif
-#if defined(WEBP_USE_SSE41)
+#if defined(WEBP_HAVE_SSE41)
if (VP8GetCPUInfo(kSSE4_1)) {
WebPInitYUV444ConvertersSSE41();
}
@@ -278,12 +278,12 @@ WEBP_DSP_INIT_FUNC(WebPInitUpsamplers) {
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
if (VP8GetCPUInfo != NULL) {
-#if defined(WEBP_USE_SSE2)
+#if defined(WEBP_HAVE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
WebPInitUpsamplersSSE2();
}
#endif
-#if defined(WEBP_USE_SSE41)
+#if defined(WEBP_HAVE_SSE41)
if (VP8GetCPUInfo(kSSE4_1)) {
WebPInitUpsamplersSSE41();
}
@@ -300,7 +300,7 @@ WEBP_DSP_INIT_FUNC(WebPInitUpsamplers) {
#endif
}
-#if defined(WEBP_USE_NEON)
+#if defined(WEBP_HAVE_NEON)
if (WEBP_NEON_OMIT_C_CODE ||
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
WebPInitUpsamplersNEON();
diff --git a/thirdparty/libwebp/src/dsp/yuv.c b/thirdparty/libwebp/src/dsp/yuv.c
index 14e67fc28e..48466f8b11 100644
--- a/thirdparty/libwebp/src/dsp/yuv.c
+++ b/thirdparty/libwebp/src/dsp/yuv.c
@@ -90,16 +90,16 @@ WEBP_DSP_INIT_FUNC(WebPInitSamplers) {
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
if (VP8GetCPUInfo != NULL) {
-#if defined(WEBP_USE_SSE2)
+#if defined(WEBP_HAVE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
WebPInitSamplersSSE2();
}
-#endif // WEBP_USE_SSE2
-#if defined(WEBP_USE_SSE41)
+#endif // WEBP_HAVE_SSE2
+#if defined(WEBP_HAVE_SSE41)
if (VP8GetCPUInfo(kSSE4_1)) {
WebPInitSamplersSSE41();
}
-#endif // WEBP_USE_SSE41
+#endif // WEBP_HAVE_SSE41
#if defined(WEBP_USE_MIPS32)
if (VP8GetCPUInfo(kMIPS32)) {
WebPInitSamplersMIPS32();
@@ -276,26 +276,26 @@ WEBP_DSP_INIT_FUNC(WebPInitConvertARGBToYUV) {
#endif
if (VP8GetCPUInfo != NULL) {
-#if defined(WEBP_USE_SSE2)
+#if defined(WEBP_HAVE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
WebPInitConvertARGBToYUVSSE2();
WebPInitSharpYUVSSE2();
}
-#endif // WEBP_USE_SSE2
-#if defined(WEBP_USE_SSE41)
+#endif // WEBP_HAVE_SSE2
+#if defined(WEBP_HAVE_SSE41)
if (VP8GetCPUInfo(kSSE4_1)) {
WebPInitConvertARGBToYUVSSE41();
}
-#endif // WEBP_USE_SSE41
+#endif // WEBP_HAVE_SSE41
}
-#if defined(WEBP_USE_NEON)
+#if defined(WEBP_HAVE_NEON)
if (WEBP_NEON_OMIT_C_CODE ||
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
WebPInitConvertARGBToYUVNEON();
WebPInitSharpYUVNEON();
}
-#endif // WEBP_USE_NEON
+#endif // WEBP_HAVE_NEON
assert(WebPConvertARGBToY != NULL);
assert(WebPConvertARGBToUV != NULL);
diff --git a/thirdparty/libwebp/src/enc/alpha_enc.c b/thirdparty/libwebp/src/enc/alpha_enc.c
index dce9ca957d..0b54f3e6ec 100644
--- a/thirdparty/libwebp/src/enc/alpha_enc.c
+++ b/thirdparty/libwebp/src/enc/alpha_enc.c
@@ -303,7 +303,7 @@ static int EncodeAlpha(VP8Encoder* const enc,
int ok = 1;
const int reduce_levels = (quality < 100);
- // quick sanity checks
+ // quick correctness checks
assert((uint64_t)data_size == (uint64_t)width * height); // as per spec
assert(enc != NULL && pic != NULL && pic->a != NULL);
assert(output != NULL && output_size != NULL);
@@ -361,7 +361,7 @@ static int EncodeAlpha(VP8Encoder* const enc,
//------------------------------------------------------------------------------
// Main calls
-static int CompressAlphaJob(void* arg1, void* dummy) {
+static int CompressAlphaJob(void* arg1, void* unused) {
VP8Encoder* const enc = (VP8Encoder*)arg1;
const WebPConfig* config = enc->config_;
uint8_t* alpha_data = NULL;
@@ -375,13 +375,13 @@ static int CompressAlphaJob(void* arg1, void* dummy) {
filter, effort_level, &alpha_data, &alpha_size)) {
return 0;
}
- if (alpha_size != (uint32_t)alpha_size) { // Sanity check.
+ if (alpha_size != (uint32_t)alpha_size) { // Soundness check.
WebPSafeFree(alpha_data);
return 0;
}
enc->alpha_data_size_ = (uint32_t)alpha_size;
enc->alpha_data_ = alpha_data;
- (void)dummy;
+ (void)unused;
return 1;
}
diff --git a/thirdparty/libwebp/src/enc/analysis_enc.c b/thirdparty/libwebp/src/enc/analysis_enc.c
index 687757ae03..ebb784261c 100644
--- a/thirdparty/libwebp/src/enc/analysis_enc.c
+++ b/thirdparty/libwebp/src/enc/analysis_enc.c
@@ -126,16 +126,6 @@ static void InitHistogram(VP8Histogram* const histo) {
histo->last_non_zero = 1;
}
-static void MergeHistograms(const VP8Histogram* const in,
- VP8Histogram* const out) {
- if (in->max_value > out->max_value) {
- out->max_value = in->max_value;
- }
- if (in->last_non_zero > out->last_non_zero) {
- out->last_non_zero = in->last_non_zero;
- }
-}
-
//------------------------------------------------------------------------------
// Simplified k-Means, to assign Nb segments based on alpha-histogram
@@ -285,49 +275,6 @@ static int FastMBAnalyze(VP8EncIterator* const it) {
return 0;
}
-static int MBAnalyzeBestIntra4Mode(VP8EncIterator* const it,
- int best_alpha) {
- uint8_t modes[16];
- const int max_mode = MAX_INTRA4_MODE;
- int i4_alpha;
- VP8Histogram total_histo;
- int cur_histo = 0;
- InitHistogram(&total_histo);
-
- VP8IteratorStartI4(it);
- do {
- int mode;
- int best_mode_alpha = DEFAULT_ALPHA;
- VP8Histogram histos[2];
- const uint8_t* const src = it->yuv_in_ + Y_OFF_ENC + VP8Scan[it->i4_];
-
- VP8MakeIntra4Preds(it);
- for (mode = 0; mode < max_mode; ++mode) {
- int alpha;
-
- InitHistogram(&histos[cur_histo]);
- VP8CollectHistogram(src, it->yuv_p_ + VP8I4ModeOffsets[mode],
- 0, 1, &histos[cur_histo]);
- alpha = GetAlpha(&histos[cur_histo]);
- if (IS_BETTER_ALPHA(alpha, best_mode_alpha)) {
- best_mode_alpha = alpha;
- modes[it->i4_] = mode;
- cur_histo ^= 1; // keep track of best histo so far.
- }
- }
- // accumulate best histogram
- MergeHistograms(&histos[cur_histo ^ 1], &total_histo);
- // Note: we reuse the original samples for predictors
- } while (VP8IteratorRotateI4(it, it->yuv_in_ + Y_OFF_ENC));
-
- i4_alpha = GetAlpha(&total_histo);
- if (IS_BETTER_ALPHA(i4_alpha, best_alpha)) {
- VP8SetIntra4Mode(it, modes);
- best_alpha = i4_alpha;
- }
- return best_alpha;
-}
-
static int MBAnalyzeBestUVMode(VP8EncIterator* const it) {
int best_alpha = DEFAULT_ALPHA;
int smallest_alpha = 0;
@@ -371,13 +318,6 @@ static void MBAnalyze(VP8EncIterator* const it,
best_alpha = FastMBAnalyze(it);
} else {
best_alpha = MBAnalyzeBestIntra16Mode(it);
- if (enc->method_ >= 5) {
- // We go and make a fast decision for intra4/intra16.
- // It's usually not a good and definitive pick, but helps seeding the
- // stats about level bit-cost.
- // TODO(skal): improve criterion.
- best_alpha = MBAnalyzeBestIntra4Mode(it, best_alpha);
- }
}
best_uv_alpha = MBAnalyzeBestUVMode(it);
diff --git a/thirdparty/libwebp/src/enc/backward_references_enc.c b/thirdparty/libwebp/src/enc/backward_references_enc.c
index d445b40fc5..519b36a091 100644
--- a/thirdparty/libwebp/src/enc/backward_references_enc.c
+++ b/thirdparty/libwebp/src/enc/backward_references_enc.c
@@ -11,13 +11,14 @@
//
#include <assert.h>
+#include <float.h>
#include <math.h>
-#include "src/enc/backward_references_enc.h"
-#include "src/enc/histogram_enc.h"
+#include "src/dsp/dsp.h"
#include "src/dsp/lossless.h"
#include "src/dsp/lossless_common.h"
-#include "src/dsp/dsp.h"
+#include "src/enc/backward_references_enc.h"
+#include "src/enc/histogram_enc.h"
#include "src/utils/color_cache_utils.h"
#include "src/utils/utils.h"
@@ -103,6 +104,20 @@ void VP8LBackwardRefsClear(VP8LBackwardRefs* const refs) {
}
}
+// Swaps the content of two VP8LBackwardRefs.
+static void BackwardRefsSwap(VP8LBackwardRefs* const refs1,
+ VP8LBackwardRefs* const refs2) {
+ const int point_to_refs1 =
+ (refs1->tail_ != NULL && refs1->tail_ == &refs1->refs_);
+ const int point_to_refs2 =
+ (refs2->tail_ != NULL && refs2->tail_ == &refs2->refs_);
+ const VP8LBackwardRefs tmp = *refs1;
+ *refs1 = *refs2;
+ *refs2 = tmp;
+ if (point_to_refs2) refs1->tail_ = &refs1->refs_;
+ if (point_to_refs1) refs2->tail_ = &refs2->refs_;
+}
+
void VP8LBackwardRefsInit(VP8LBackwardRefs* const refs, int block_size) {
assert(refs != NULL);
memset(refs, 0, sizeof(*refs));
@@ -154,6 +169,22 @@ static PixOrCopyBlock* BackwardRefsNewBlock(VP8LBackwardRefs* const refs) {
return b;
}
+// Return 1 on success, 0 on error.
+static int BackwardRefsClone(const VP8LBackwardRefs* const from,
+ VP8LBackwardRefs* const to) {
+ const PixOrCopyBlock* block_from = from->refs_;
+ VP8LClearBackwardRefs(to);
+ while (block_from != NULL) {
+ PixOrCopyBlock* const block_to = BackwardRefsNewBlock(to);
+ if (block_to == NULL) return 0;
+ memcpy(block_to->start_, block_from->start_,
+ block_from->size_ * sizeof(PixOrCopy));
+ block_to->size_ = block_from->size_;
+ block_from = block_from->next_;
+ }
+ return 1;
+}
+
extern void VP8LBackwardRefsCursorAdd(VP8LBackwardRefs* const refs,
const PixOrCopy v);
void VP8LBackwardRefsCursorAdd(VP8LBackwardRefs* const refs,
@@ -753,12 +784,18 @@ static int CalculateBestCacheSize(const uint32_t* argb, int quality,
}
}
} else {
+ int code, extra_bits, extra_bits_value;
// We should compute the contribution of the (distance,length)
// histograms but those are the same independently from the cache size.
// As those constant contributions are in the end added to the other
- // histogram contributions, we can safely ignore them.
+ // histogram contributions, we can ignore them, except for the length
+ // prefix that is part of the literal_ histogram.
int len = PixOrCopyLength(v);
uint32_t argb_prev = *argb ^ 0xffffffffu;
+ VP8LPrefixEncode(len, &code, &extra_bits, &extra_bits_value);
+ for (i = 0; i <= cache_bits_max; ++i) {
+ ++histos[i]->literal_[NUM_LITERAL_CODES + code];
+ }
// Update the color caches.
do {
if (*argb != argb_prev) {
@@ -842,16 +879,21 @@ extern int VP8LBackwardReferencesTraceBackwards(
int xsize, int ysize, const uint32_t* const argb, int cache_bits,
const VP8LHashChain* const hash_chain,
const VP8LBackwardRefs* const refs_src, VP8LBackwardRefs* const refs_dst);
-static VP8LBackwardRefs* GetBackwardReferences(
- int width, int height, const uint32_t* const argb, int quality,
- int lz77_types_to_try, int* const cache_bits,
- const VP8LHashChain* const hash_chain, VP8LBackwardRefs* best,
- VP8LBackwardRefs* worst) {
- const int cache_bits_initial = *cache_bits;
- double bit_cost_best = -1;
+static int GetBackwardReferences(int width, int height,
+ const uint32_t* const argb, int quality,
+ int lz77_types_to_try, int cache_bits_max,
+ int do_no_cache,
+ const VP8LHashChain* const hash_chain,
+ VP8LBackwardRefs* const refs,
+ int* const cache_bits_best) {
VP8LHistogram* histo = NULL;
- int lz77_type, lz77_type_best = 0;
+ int i, lz77_type;
+ // Index 0 is for a color cache, index 1 for no cache (if needed).
+ int lz77_types_best[2] = {0, 0};
+ double bit_costs_best[2] = {DBL_MAX, DBL_MAX};
VP8LHashChain hash_chain_box;
+ VP8LBackwardRefs* const refs_tmp = &refs[do_no_cache ? 2 : 1];
+ int status = 0;
memset(&hash_chain_box, 0, sizeof(hash_chain_box));
histo = VP8LAllocateHistogram(MAX_COLOR_CACHE_BITS);
@@ -860,86 +902,129 @@ static VP8LBackwardRefs* GetBackwardReferences(
for (lz77_type = 1; lz77_types_to_try;
lz77_types_to_try &= ~lz77_type, lz77_type <<= 1) {
int res = 0;
- double bit_cost;
- int cache_bits_tmp = cache_bits_initial;
+ double bit_cost = 0.;
if ((lz77_types_to_try & lz77_type) == 0) continue;
switch (lz77_type) {
case kLZ77RLE:
- res = BackwardReferencesRle(width, height, argb, 0, worst);
+ res = BackwardReferencesRle(width, height, argb, 0, refs_tmp);
break;
case kLZ77Standard:
// Compute LZ77 with no cache (0 bits), as the ideal LZ77 with a color
// cache is not that different in practice.
- res = BackwardReferencesLz77(width, height, argb, 0, hash_chain, worst);
+ res = BackwardReferencesLz77(width, height, argb, 0, hash_chain,
+ refs_tmp);
break;
case kLZ77Box:
if (!VP8LHashChainInit(&hash_chain_box, width * height)) goto Error;
res = BackwardReferencesLz77Box(width, height, argb, 0, hash_chain,
- &hash_chain_box, worst);
+ &hash_chain_box, refs_tmp);
break;
default:
assert(0);
}
if (!res) goto Error;
- // Next, try with a color cache and update the references.
- if (!CalculateBestCacheSize(argb, quality, worst, &cache_bits_tmp)) {
- goto Error;
- }
- if (cache_bits_tmp > 0) {
- if (!BackwardRefsWithLocalCache(argb, cache_bits_tmp, worst)) {
- goto Error;
+ // Start with the no color cache case.
+ for (i = 1; i >= 0; --i) {
+ int cache_bits = (i == 1) ? 0 : cache_bits_max;
+
+ if (i == 1 && !do_no_cache) continue;
+
+ if (i == 0) {
+ // Try with a color cache.
+ if (!CalculateBestCacheSize(argb, quality, refs_tmp, &cache_bits)) {
+ goto Error;
+ }
+ if (cache_bits > 0) {
+ if (!BackwardRefsWithLocalCache(argb, cache_bits, refs_tmp)) {
+ goto Error;
+ }
+ }
}
- }
- // Keep the best backward references.
- VP8LHistogramCreate(histo, worst, cache_bits_tmp);
- bit_cost = VP8LHistogramEstimateBits(histo);
- if (lz77_type_best == 0 || bit_cost < bit_cost_best) {
- VP8LBackwardRefs* const tmp = worst;
- worst = best;
- best = tmp;
- bit_cost_best = bit_cost;
- *cache_bits = cache_bits_tmp;
- lz77_type_best = lz77_type;
+ if (i == 0 && do_no_cache && cache_bits == 0) {
+ // No need to re-compute bit_cost as it was computed at i == 1.
+ } else {
+ VP8LHistogramCreate(histo, refs_tmp, cache_bits);
+ bit_cost = VP8LHistogramEstimateBits(histo);
+ }
+
+ if (bit_cost < bit_costs_best[i]) {
+ if (i == 1) {
+ // Do not swap as the full cache analysis would have the wrong
+ // VP8LBackwardRefs to start with.
+ if (!BackwardRefsClone(refs_tmp, &refs[1])) goto Error;
+ } else {
+ BackwardRefsSwap(refs_tmp, &refs[0]);
+ }
+ bit_costs_best[i] = bit_cost;
+ lz77_types_best[i] = lz77_type;
+ if (i == 0) *cache_bits_best = cache_bits;
+ }
}
}
- assert(lz77_type_best > 0);
+ assert(lz77_types_best[0] > 0);
+ assert(!do_no_cache || lz77_types_best[1] > 0);
// Improve on simple LZ77 but only for high quality (TraceBackwards is
// costly).
- if ((lz77_type_best == kLZ77Standard || lz77_type_best == kLZ77Box) &&
- quality >= 25) {
- const VP8LHashChain* const hash_chain_tmp =
- (lz77_type_best == kLZ77Standard) ? hash_chain : &hash_chain_box;
- if (VP8LBackwardReferencesTraceBackwards(width, height, argb, *cache_bits,
- hash_chain_tmp, best, worst)) {
- double bit_cost_trace;
- VP8LHistogramCreate(histo, worst, *cache_bits);
- bit_cost_trace = VP8LHistogramEstimateBits(histo);
- if (bit_cost_trace < bit_cost_best) best = worst;
+ for (i = 1; i >= 0; --i) {
+ if (i == 1 && !do_no_cache) continue;
+ if ((lz77_types_best[i] == kLZ77Standard ||
+ lz77_types_best[i] == kLZ77Box) &&
+ quality >= 25) {
+ const VP8LHashChain* const hash_chain_tmp =
+ (lz77_types_best[i] == kLZ77Standard) ? hash_chain : &hash_chain_box;
+ const int cache_bits = (i == 1) ? 0 : *cache_bits_best;
+ if (VP8LBackwardReferencesTraceBackwards(width, height, argb, cache_bits,
+ hash_chain_tmp, &refs[i],
+ refs_tmp)) {
+ double bit_cost_trace;
+ VP8LHistogramCreate(histo, refs_tmp, cache_bits);
+ bit_cost_trace = VP8LHistogramEstimateBits(histo);
+ if (bit_cost_trace < bit_costs_best[i]) {
+ BackwardRefsSwap(refs_tmp, &refs[i]);
+ }
+ }
}
- }
- BackwardReferences2DLocality(width, best);
+ BackwardReferences2DLocality(width, &refs[i]);
+
+ if (i == 1 && lz77_types_best[0] == lz77_types_best[1] &&
+ *cache_bits_best == 0) {
+ // If the best cache size is 0 and we have the same best LZ77, just copy
+ // the data over and stop here.
+ if (!BackwardRefsClone(&refs[1], &refs[0])) goto Error;
+ break;
+ }
+ }
+ status = 1;
Error:
VP8LHashChainClear(&hash_chain_box);
VP8LFreeHistogram(histo);
- return best;
+ return status;
}
-VP8LBackwardRefs* VP8LGetBackwardReferences(
+WebPEncodingError VP8LGetBackwardReferences(
int width, int height, const uint32_t* const argb, int quality,
- int low_effort, int lz77_types_to_try, int* const cache_bits,
- const VP8LHashChain* const hash_chain, VP8LBackwardRefs* const refs_tmp1,
- VP8LBackwardRefs* const refs_tmp2) {
+ int low_effort, int lz77_types_to_try, int cache_bits_max, int do_no_cache,
+ const VP8LHashChain* const hash_chain, VP8LBackwardRefs* const refs,
+ int* const cache_bits_best) {
if (low_effort) {
- return GetBackwardReferencesLowEffort(width, height, argb, cache_bits,
- hash_chain, refs_tmp1);
+ VP8LBackwardRefs* refs_best;
+ *cache_bits_best = cache_bits_max;
+ refs_best = GetBackwardReferencesLowEffort(
+ width, height, argb, cache_bits_best, hash_chain, refs);
+ if (refs_best == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY;
+ // Set it in first position.
+ BackwardRefsSwap(refs_best, &refs[0]);
} else {
- return GetBackwardReferences(width, height, argb, quality,
- lz77_types_to_try, cache_bits, hash_chain,
- refs_tmp1, refs_tmp2);
+ if (!GetBackwardReferences(width, height, argb, quality, lz77_types_to_try,
+ cache_bits_max, do_no_cache, hash_chain, refs,
+ cache_bits_best)) {
+ return VP8_ENC_ERROR_OUT_OF_MEMORY;
+ }
}
+ return VP8_ENC_OK;
}
diff --git a/thirdparty/libwebp/src/enc/backward_references_enc.h b/thirdparty/libwebp/src/enc/backward_references_enc.h
index 103ddfdcb7..4c0267b41e 100644
--- a/thirdparty/libwebp/src/enc/backward_references_enc.h
+++ b/thirdparty/libwebp/src/enc/backward_references_enc.h
@@ -16,6 +16,7 @@
#include <assert.h>
#include <stdlib.h>
#include "src/webp/types.h"
+#include "src/webp/encode.h"
#include "src/webp/format_constants.h"
#ifdef __cplusplus
@@ -218,14 +219,19 @@ enum VP8LLZ77Type {
// Evaluates best possible backward references for specified quality.
// The input cache_bits to 'VP8LGetBackwardReferences' sets the maximum cache
// bits to use (passing 0 implies disabling the local color cache).
-// The optimal cache bits is evaluated and set for the *cache_bits parameter.
-// The return value is the pointer to the best of the two backward refs viz,
-// refs[0] or refs[1].
-VP8LBackwardRefs* VP8LGetBackwardReferences(
+// The optimal cache bits is evaluated and set for the *cache_bits_best
+// parameter with the matching refs_best.
+// If do_no_cache == 0, refs is an array of 2 values and the best
+// VP8LBackwardRefs is put in the first element.
+// If do_no_cache != 0, refs is an array of 3 values and the best
+// VP8LBackwardRefs is put in the first element, the best value with no-cache in
+// the second element.
+// In both cases, the last element is used as temporary internally.
+WebPEncodingError VP8LGetBackwardReferences(
int width, int height, const uint32_t* const argb, int quality,
- int low_effort, int lz77_types_to_try, int* const cache_bits,
- const VP8LHashChain* const hash_chain, VP8LBackwardRefs* const refs_tmp1,
- VP8LBackwardRefs* const refs_tmp2);
+ int low_effort, int lz77_types_to_try, int cache_bits_max, int do_no_cache,
+ const VP8LHashChain* const hash_chain, VP8LBackwardRefs* const refs,
+ int* const cache_bits_best);
#ifdef __cplusplus
}
diff --git a/thirdparty/libwebp/src/enc/config_enc.c b/thirdparty/libwebp/src/enc/config_enc.c
index 9d4828978e..3518b41403 100644
--- a/thirdparty/libwebp/src/enc/config_enc.c
+++ b/thirdparty/libwebp/src/enc/config_enc.c
@@ -39,6 +39,8 @@ int WebPConfigInitInternal(WebPConfig* config,
config->partitions = 0;
config->segments = 4;
config->pass = 1;
+ config->qmin = 0;
+ config->qmax = 100;
config->show_compressed = 0;
config->preprocessing = 0;
config->autofilter = 0;
@@ -106,6 +108,9 @@ int WebPValidateConfig(const WebPConfig* config) {
if (config->filter_type < 0 || config->filter_type > 1) return 0;
if (config->autofilter < 0 || config->autofilter > 1) return 0;
if (config->pass < 1 || config->pass > 10) return 0;
+ if (config->qmin < 0 || config->qmax > 100 || config->qmin > config->qmax) {
+ return 0;
+ }
if (config->show_compressed < 0 || config->show_compressed > 1) return 0;
if (config->preprocessing < 0 || config->preprocessing > 7) return 0;
if (config->partitions < 0 || config->partitions > 3) return 0;
diff --git a/thirdparty/libwebp/src/enc/frame_enc.c b/thirdparty/libwebp/src/enc/frame_enc.c
index 1aec376e44..af538d83ba 100644
--- a/thirdparty/libwebp/src/enc/frame_enc.c
+++ b/thirdparty/libwebp/src/enc/frame_enc.c
@@ -31,10 +31,15 @@
// we allow 2k of extra head-room in PARTITION0 limit.
#define PARTITION0_SIZE_LIMIT ((VP8_MAX_PARTITION0_SIZE - 2048ULL) << 11)
+static float Clamp(float v, float min, float max) {
+ return (v < min) ? min : (v > max) ? max : v;
+}
+
typedef struct { // struct for organizing convergence in either size or PSNR
int is_first;
float dq;
float q, last_q;
+ float qmin, qmax;
double value, last_value; // PSNR or size
double target;
int do_size_search;
@@ -47,7 +52,9 @@ static int InitPassStats(const VP8Encoder* const enc, PassStats* const s) {
s->is_first = 1;
s->dq = 10.f;
- s->q = s->last_q = enc->config_->quality;
+ s->qmin = 1.f * enc->config_->qmin;
+ s->qmax = 1.f * enc->config_->qmax;
+ s->q = s->last_q = Clamp(enc->config_->quality, s->qmin, s->qmax);
s->target = do_size_search ? (double)target_size
: (target_PSNR > 0.) ? target_PSNR
: 40.; // default, just in case
@@ -56,10 +63,6 @@ static int InitPassStats(const VP8Encoder* const enc, PassStats* const s) {
return do_size_search;
}
-static float Clamp(float v, float min, float max) {
- return (v < min) ? min : (v > max) ? max : v;
-}
-
static float ComputeNextQ(PassStats* const s) {
float dq;
if (s->is_first) {
@@ -75,7 +78,7 @@ static float ComputeNextQ(PassStats* const s) {
s->dq = Clamp(dq, -30.f, 30.f);
s->last_q = s->q;
s->last_value = s->value;
- s->q = Clamp(s->q + s->dq, 0.f, 100.f);
+ s->q = Clamp(s->q + s->dq, s->qmin, s->qmax);
return s->q;
}
@@ -848,9 +851,10 @@ int VP8EncTokenLoop(VP8Encoder* const enc) {
}
#if (DEBUG_SEARCH > 0)
- printf("#%2d metric:%.1lf -> %.1lf last_q=%.2lf q=%.2lf dq=%.2lf\n",
+ printf("#%2d metric:%.1lf -> %.1lf last_q=%.2lf q=%.2lf dq=%.2lf "
+ " range:[%.1f, %.1f]\n",
num_pass_left, stats.last_value, stats.value,
- stats.last_q, stats.q, stats.dq);
+ stats.last_q, stats.q, stats.dq, stats.qmin, stats.qmax);
#endif
if (enc->max_i4_header_bits_ > 0 && size_p0 > PARTITION0_SIZE_LIMIT) {
++num_pass_left;
diff --git a/thirdparty/libwebp/src/enc/histogram_enc.c b/thirdparty/libwebp/src/enc/histogram_enc.c
index a4e6bf3a98..38a0cebcab 100644
--- a/thirdparty/libwebp/src/enc/histogram_enc.c
+++ b/thirdparty/libwebp/src/enc/histogram_enc.c
@@ -208,6 +208,7 @@ void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const histo,
} else if (PixOrCopyIsCacheIdx(v)) {
const int literal_ix =
NUM_LITERAL_CODES + NUM_LENGTH_CODES + PixOrCopyCacheIdx(v);
+ assert(histo->palette_code_bits_ != 0);
++histo->literal_[literal_ix];
} else {
int code, extra_bits;
@@ -1170,13 +1171,15 @@ static void RemoveEmptyHistograms(VP8LHistogramSet* const image_histo) {
int VP8LGetHistoImageSymbols(int xsize, int ysize,
const VP8LBackwardRefs* const refs,
int quality, int low_effort,
- int histo_bits, int cache_bits,
+ int histogram_bits, int cache_bits,
VP8LHistogramSet* const image_histo,
VP8LHistogram* const tmp_histo,
uint16_t* const histogram_symbols) {
int ok = 0;
- const int histo_xsize = histo_bits ? VP8LSubSampleSize(xsize, histo_bits) : 1;
- const int histo_ysize = histo_bits ? VP8LSubSampleSize(ysize, histo_bits) : 1;
+ const int histo_xsize =
+ histogram_bits ? VP8LSubSampleSize(xsize, histogram_bits) : 1;
+ const int histo_ysize =
+ histogram_bits ? VP8LSubSampleSize(ysize, histogram_bits) : 1;
const int image_histo_raw_size = histo_xsize * histo_ysize;
VP8LHistogramSet* const orig_histo =
VP8LAllocateHistogramSet(image_histo_raw_size, cache_bits);
@@ -1192,7 +1195,7 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
if (orig_histo == NULL || map_tmp == NULL) goto Error;
// Construct the histograms from backward references.
- HistogramBuild(xsize, histo_bits, refs, orig_histo);
+ HistogramBuild(xsize, histogram_bits, refs, orig_histo);
// Copies the histograms and computes its bit_cost.
// histogram_symbols is optimized
HistogramCopyAndAnalyze(orig_histo, image_histo, &num_used,
diff --git a/thirdparty/libwebp/src/enc/histogram_enc.h b/thirdparty/libwebp/src/enc/histogram_enc.h
index 54c2d21783..c3428b5d55 100644
--- a/thirdparty/libwebp/src/enc/histogram_enc.h
+++ b/thirdparty/libwebp/src/enc/histogram_enc.h
@@ -64,8 +64,8 @@ void VP8LHistogramCreate(VP8LHistogram* const p,
const VP8LBackwardRefs* const refs,
int palette_code_bits);
-// Return the size of the histogram for a given palette_code_bits.
-int VP8LGetHistogramSize(int palette_code_bits);
+// Return the size of the histogram for a given cache_bits.
+int VP8LGetHistogramSize(int cache_bits);
// Set the palette_code_bits and reset the stats.
// If init_arrays is true, the arrays are also filled with 0's.
@@ -110,7 +110,7 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
const VP8LBackwardRefs* const refs,
int quality, int low_effort,
int histogram_bits, int cache_bits,
- VP8LHistogramSet* const image_in,
+ VP8LHistogramSet* const image_histo,
VP8LHistogram* const tmp_histo,
uint16_t* const histogram_symbols);
diff --git a/thirdparty/libwebp/src/enc/picture_csp_enc.c b/thirdparty/libwebp/src/enc/picture_csp_enc.c
index 718e014ed2..35eede9635 100644
--- a/thirdparty/libwebp/src/enc/picture_csp_enc.c
+++ b/thirdparty/libwebp/src/enc/picture_csp_enc.c
@@ -61,16 +61,14 @@ static int CheckNonOpaque(const uint8_t* alpha, int width, int height,
// Checking for the presence of non-opaque alpha.
int WebPPictureHasTransparency(const WebPPicture* picture) {
if (picture == NULL) return 0;
- if (!picture->use_argb) {
- return CheckNonOpaque(picture->a, picture->width, picture->height,
- 1, picture->a_stride);
- } else {
+ if (picture->use_argb) {
const int alpha_offset = ALPHA_OFFSET;
return CheckNonOpaque((const uint8_t*)picture->argb + alpha_offset,
picture->width, picture->height,
4, picture->argb_stride * sizeof(*picture->argb));
}
- return 0;
+ return CheckNonOpaque(picture->a, picture->width, picture->height,
+ 1, picture->a_stride);
}
//------------------------------------------------------------------------------
@@ -90,8 +88,9 @@ int WebPPictureHasTransparency(const WebPPicture* picture) {
static int kLinearToGammaTab[kGammaTabSize + 1];
static uint16_t kGammaToLinearTab[256];
static volatile int kGammaTablesOk = 0;
+static void InitGammaTables(void);
-static WEBP_TSAN_IGNORE_FUNCTION void InitGammaTables(void) {
+WEBP_DSP_INIT_FUNC(InitGammaTables) {
if (!kGammaTablesOk) {
int v;
const double scale = (double)(1 << kGammaTabFix) / kGammaScale;
@@ -181,8 +180,9 @@ static uint32_t kLinearToGammaTabS[kGammaTabSize + 2];
#define GAMMA_TO_LINEAR_BITS 14
static uint32_t kGammaToLinearTabS[MAX_Y_T + 1]; // size scales with Y_FIX
static volatile int kGammaTablesSOk = 0;
+static void InitGammaTablesS(void);
-static WEBP_TSAN_IGNORE_FUNCTION void InitGammaTablesS(void) {
+WEBP_DSP_INIT_FUNC(InitGammaTablesS) {
assert(2 * GAMMA_TO_LINEAR_BITS < 32); // we use uint32_t intermediate values
if (!kGammaTablesSOk) {
int v;
diff --git a/thirdparty/libwebp/src/enc/picture_rescale_enc.c b/thirdparty/libwebp/src/enc/picture_rescale_enc.c
index 58a6ae7b9d..a75f5d9c06 100644
--- a/thirdparty/libwebp/src/enc/picture_rescale_enc.c
+++ b/thirdparty/libwebp/src/enc/picture_rescale_enc.c
@@ -164,22 +164,25 @@ int WebPPictureCrop(WebPPicture* pic,
//------------------------------------------------------------------------------
// Simple picture rescaler
-static void RescalePlane(const uint8_t* src,
- int src_width, int src_height, int src_stride,
- uint8_t* dst,
- int dst_width, int dst_height, int dst_stride,
- rescaler_t* const work,
- int num_channels) {
+static int RescalePlane(const uint8_t* src,
+ int src_width, int src_height, int src_stride,
+ uint8_t* dst,
+ int dst_width, int dst_height, int dst_stride,
+ rescaler_t* const work,
+ int num_channels) {
WebPRescaler rescaler;
int y = 0;
- WebPRescalerInit(&rescaler, src_width, src_height,
- dst, dst_width, dst_height, dst_stride,
- num_channels, work);
+ if (!WebPRescalerInit(&rescaler, src_width, src_height,
+ dst, dst_width, dst_height, dst_stride,
+ num_channels, work)) {
+ return 0;
+ }
while (y < src_height) {
y += WebPRescalerImport(&rescaler, src_height - y,
src + y * src_stride, src_stride);
WebPRescalerExport(&rescaler);
}
+ return 1;
}
static void AlphaMultiplyARGB(WebPPicture* const pic, int inverse) {
@@ -222,25 +225,28 @@ int WebPPictureRescale(WebPPicture* pic, int width, int height) {
// If present, we need to rescale alpha first (for AlphaMultiplyY).
if (pic->a != NULL) {
WebPInitAlphaProcessing();
- RescalePlane(pic->a, prev_width, prev_height, pic->a_stride,
- tmp.a, width, height, tmp.a_stride, work, 1);
+ if (!RescalePlane(pic->a, prev_width, prev_height, pic->a_stride,
+ tmp.a, width, height, tmp.a_stride, work, 1)) {
+ return 0;
+ }
}
// We take transparency into account on the luma plane only. That's not
// totally exact blending, but still is a good approximation.
AlphaMultiplyY(pic, 0);
- RescalePlane(pic->y, prev_width, prev_height, pic->y_stride,
- tmp.y, width, height, tmp.y_stride, work, 1);
+ if (!RescalePlane(pic->y, prev_width, prev_height, pic->y_stride,
+ tmp.y, width, height, tmp.y_stride, work, 1) ||
+ !RescalePlane(pic->u,
+ HALVE(prev_width), HALVE(prev_height), pic->uv_stride,
+ tmp.u,
+ HALVE(width), HALVE(height), tmp.uv_stride, work, 1) ||
+ !RescalePlane(pic->v,
+ HALVE(prev_width), HALVE(prev_height), pic->uv_stride,
+ tmp.v,
+ HALVE(width), HALVE(height), tmp.uv_stride, work, 1)) {
+ return 0;
+ }
AlphaMultiplyY(&tmp, 1);
-
- RescalePlane(pic->u,
- HALVE(prev_width), HALVE(prev_height), pic->uv_stride,
- tmp.u,
- HALVE(width), HALVE(height), tmp.uv_stride, work, 1);
- RescalePlane(pic->v,
- HALVE(prev_width), HALVE(prev_height), pic->uv_stride,
- tmp.v,
- HALVE(width), HALVE(height), tmp.uv_stride, work, 1);
} else {
work = (rescaler_t*)WebPSafeMalloc(2ULL * width * 4, sizeof(*work));
if (work == NULL) {
@@ -252,11 +258,12 @@ int WebPPictureRescale(WebPPicture* pic, int width, int height) {
// the premultiplication afterward (while preserving the alpha channel).
WebPInitAlphaProcessing();
AlphaMultiplyARGB(pic, 0);
- RescalePlane((const uint8_t*)pic->argb, prev_width, prev_height,
- pic->argb_stride * 4,
- (uint8_t*)tmp.argb, width, height,
- tmp.argb_stride * 4,
- work, 4);
+ if (!RescalePlane((const uint8_t*)pic->argb, prev_width, prev_height,
+ pic->argb_stride * 4,
+ (uint8_t*)tmp.argb, width, height,
+ tmp.argb_stride * 4, work, 4)) {
+ return 0;
+ }
AlphaMultiplyARGB(&tmp, 1);
}
WebPPictureFree(pic);
diff --git a/thirdparty/libwebp/src/enc/picture_tools_enc.c b/thirdparty/libwebp/src/enc/picture_tools_enc.c
index d0e8a495da..38cb01534a 100644
--- a/thirdparty/libwebp/src/enc/picture_tools_enc.c
+++ b/thirdparty/libwebp/src/enc/picture_tools_enc.c
@@ -83,6 +83,19 @@ static int SmoothenBlock(const uint8_t* a_ptr, int a_stride, uint8_t* y_ptr,
return (count == 0);
}
+void WebPReplaceTransparentPixels(WebPPicture* const pic, uint32_t color) {
+ if (pic != NULL && pic->use_argb) {
+ int y = pic->height;
+ uint32_t* argb = pic->argb;
+ color &= 0xffffffu; // force alpha=0
+ WebPInitAlphaProcessing();
+ while (y-- > 0) {
+ WebPAlphaReplace(argb, pic->width, color);
+ argb += pic->argb_stride;
+ }
+ }
+}
+
void WebPCleanupTransparentArea(WebPPicture* pic) {
int x, y, w, h;
if (pic == NULL) return;
@@ -165,24 +178,6 @@ void WebPCleanupTransparentArea(WebPPicture* pic) {
#undef SIZE
#undef SIZE2
-void WebPCleanupTransparentAreaLossless(WebPPicture* const pic) {
- int x, y, w, h;
- uint32_t* argb;
- assert(pic != NULL && pic->use_argb);
- w = pic->width;
- h = pic->height;
- argb = pic->argb;
-
- for (y = 0; y < h; ++y) {
- for (x = 0; x < w; ++x) {
- if ((argb[x] & 0xff000000) == 0) {
- argb[x] = 0x00000000;
- }
- }
- argb += pic->argb_stride;
- }
-}
-
//------------------------------------------------------------------------------
// Blend color and remove transparency info
diff --git a/thirdparty/libwebp/src/enc/syntax_enc.c b/thirdparty/libwebp/src/enc/syntax_enc.c
index a9e5a6cf0f..e18cf650ca 100644
--- a/thirdparty/libwebp/src/enc/syntax_enc.c
+++ b/thirdparty/libwebp/src/enc/syntax_enc.c
@@ -349,7 +349,7 @@ int VP8EncWrite(VP8Encoder* const enc) {
(enc->alpha_data_size_ & 1);
riff_size += CHUNK_HEADER_SIZE + padded_alpha_size;
}
- // Sanity check.
+ // RIFF size should fit in 32-bits.
if (riff_size > 0xfffffffeU) {
return WebPEncodingSetError(pic, VP8_ENC_ERROR_FILE_TOO_BIG);
}
diff --git a/thirdparty/libwebp/src/enc/vp8i_enc.h b/thirdparty/libwebp/src/enc/vp8i_enc.h
index fedcaeea27..67e9509367 100644
--- a/thirdparty/libwebp/src/enc/vp8i_enc.h
+++ b/thirdparty/libwebp/src/enc/vp8i_enc.h
@@ -31,8 +31,8 @@ extern "C" {
// version numbers
#define ENC_MAJ_VERSION 1
-#define ENC_MIN_VERSION 1
-#define ENC_REV_VERSION 0
+#define ENC_MIN_VERSION 2
+#define ENC_REV_VERSION 1
enum { MAX_LF_LEVELS = 64, // Maximum loop filter level
MAX_VARIABLE_LEVEL = 67, // last (inclusive) level with variable cost
@@ -286,8 +286,7 @@ int VP8IteratorNext(VP8EncIterator* const it);
// save the yuv_out_ boundary values to top_/left_ arrays for next iterations.
void VP8IteratorSaveBoundary(VP8EncIterator* const it);
// Report progression based on macroblock rows. Return 0 for user-abort request.
-int VP8IteratorProgress(const VP8EncIterator* const it,
- int final_delta_percent);
+int VP8IteratorProgress(const VP8EncIterator* const it, int delta);
// Intra4x4 iterations
void VP8IteratorStartI4(VP8EncIterator* const it);
// returns true if not done.
@@ -505,9 +504,9 @@ int WebPPictureAllocARGB(WebPPicture* const picture, int width, int height);
// Returns false in case of error (invalid param, out-of-memory).
int WebPPictureAllocYUVA(WebPPicture* const picture, int width, int height);
-// Clean-up the RGB samples under fully transparent area, to help lossless
-// compressibility (no guarantee, though). Assumes that pic->use_argb is true.
-void WebPCleanupTransparentAreaLossless(WebPPicture* const pic);
+// Replace samples that are fully transparent by 'color' to help compressibility
+// (no guarantee, though). Assumes pic->use_argb is true.
+void WebPReplaceTransparentPixels(WebPPicture* const pic, uint32_t color);
//------------------------------------------------------------------------------
diff --git a/thirdparty/libwebp/src/enc/vp8l_enc.c b/thirdparty/libwebp/src/enc/vp8l_enc.c
index 2efd403f77..e330e716f1 100644
--- a/thirdparty/libwebp/src/enc/vp8l_enc.c
+++ b/thirdparty/libwebp/src/enc/vp8l_enc.c
@@ -65,25 +65,22 @@ static WEBP_INLINE void SwapColor(uint32_t* const col1, uint32_t* const col2) {
*col2 = tmp;
}
-static void GreedyMinimizeDeltas(uint32_t palette[], int num_colors) {
- // Find greedily always the closest color of the predicted color to minimize
- // deltas in the palette. This reduces storage needs since the
- // palette is stored with delta encoding.
- uint32_t predict = 0x00000000;
- int i, k;
- for (i = 0; i < num_colors; ++i) {
- int best_ix = i;
- uint32_t best_score = ~0U;
- for (k = i; k < num_colors; ++k) {
- const uint32_t cur_score = PaletteColorDistance(palette[k], predict);
- if (best_score > cur_score) {
- best_score = cur_score;
- best_ix = k;
- }
+static WEBP_INLINE int SearchColorNoIdx(const uint32_t sorted[], uint32_t color,
+ int num_colors) {
+ int low = 0, hi = num_colors;
+ if (sorted[low] == color) return low; // loop invariant: sorted[low] != color
+ while (1) {
+ const int mid = (low + hi) >> 1;
+ if (sorted[mid] == color) {
+ return mid;
+ } else if (sorted[mid] < color) {
+ low = mid;
+ } else {
+ hi = mid;
}
- SwapColor(&palette[best_ix], &palette[i]);
- predict = palette[i];
}
+ assert(0);
+ return 0;
}
// The palette has been sorted by alpha. This function checks if the other
@@ -92,7 +89,8 @@ static void GreedyMinimizeDeltas(uint32_t palette[], int num_colors) {
// no benefit to re-organize them greedily. A monotonic development
// would be spotted in green-only situations (like lossy alpha) or gray-scale
// images.
-static int PaletteHasNonMonotonousDeltas(uint32_t palette[], int num_colors) {
+static int PaletteHasNonMonotonousDeltas(const uint32_t* const palette,
+ int num_colors) {
uint32_t predict = 0x000000;
int i;
uint8_t sign_found = 0x00;
@@ -115,28 +113,215 @@ static int PaletteHasNonMonotonousDeltas(uint32_t palette[], int num_colors) {
return (sign_found & (sign_found << 1)) != 0; // two consequent signs.
}
+static void PaletteSortMinimizeDeltas(const uint32_t* const palette_sorted,
+ int num_colors, uint32_t* const palette) {
+ uint32_t predict = 0x00000000;
+ int i, k;
+ memcpy(palette, palette_sorted, num_colors * sizeof(*palette));
+ if (!PaletteHasNonMonotonousDeltas(palette_sorted, num_colors)) return;
+ // Find greedily always the closest color of the predicted color to minimize
+ // deltas in the palette. This reduces storage needs since the
+ // palette is stored with delta encoding.
+ for (i = 0; i < num_colors; ++i) {
+ int best_ix = i;
+ uint32_t best_score = ~0U;
+ for (k = i; k < num_colors; ++k) {
+ const uint32_t cur_score = PaletteColorDistance(palette[k], predict);
+ if (best_score > cur_score) {
+ best_score = cur_score;
+ best_ix = k;
+ }
+ }
+ SwapColor(&palette[best_ix], &palette[i]);
+ predict = palette[i];
+ }
+}
+
+// Sort palette in increasing order and prepare an inverse mapping array.
+static void PrepareMapToPalette(const uint32_t palette[], uint32_t num_colors,
+ uint32_t sorted[], uint32_t idx_map[]) {
+ uint32_t i;
+ memcpy(sorted, palette, num_colors * sizeof(*sorted));
+ qsort(sorted, num_colors, sizeof(*sorted), PaletteCompareColorsForQsort);
+ for (i = 0; i < num_colors; ++i) {
+ idx_map[SearchColorNoIdx(sorted, palette[i], num_colors)] = i;
+ }
+}
+
// -----------------------------------------------------------------------------
-// Palette
+// Modified Zeng method from "A Survey on Palette Reordering
+// Methods for Improving the Compression of Color-Indexed Images" by Armando J.
+// Pinho and Antonio J. R. Neves.
+
+// Finds the biggest cooccurrence in the matrix.
+static void CoOccurrenceFindMax(const uint32_t* const cooccurrence,
+ uint32_t num_colors, uint8_t* const c1,
+ uint8_t* const c2) {
+ // Find the index that is most frequently located adjacent to other
+ // (different) indexes.
+ uint32_t best_sum = 0u;
+ uint32_t i, j, best_cooccurrence;
+ *c1 = 0u;
+ for (i = 0; i < num_colors; ++i) {
+ uint32_t sum = 0;
+ for (j = 0; j < num_colors; ++j) sum += cooccurrence[i * num_colors + j];
+ if (sum > best_sum) {
+ best_sum = sum;
+ *c1 = i;
+ }
+ }
+ // Find the index that is most frequently found adjacent to *c1.
+ *c2 = 0u;
+ best_cooccurrence = 0u;
+ for (i = 0; i < num_colors; ++i) {
+ if (cooccurrence[*c1 * num_colors + i] > best_cooccurrence) {
+ best_cooccurrence = cooccurrence[*c1 * num_colors + i];
+ *c2 = i;
+ }
+ }
+ assert(*c1 != *c2);
+}
-// If number of colors in the image is less than or equal to MAX_PALETTE_SIZE,
-// creates a palette and returns true, else returns false.
-static int AnalyzeAndCreatePalette(const WebPPicture* const pic,
- int low_effort,
- uint32_t palette[MAX_PALETTE_SIZE],
- int* const palette_size) {
- const int num_colors = WebPGetColorPalette(pic, palette);
- if (num_colors > MAX_PALETTE_SIZE) {
- *palette_size = 0;
- return 0;
+// Builds the cooccurrence matrix
+static WebPEncodingError CoOccurrenceBuild(const WebPPicture* const pic,
+ const uint32_t* const palette,
+ uint32_t num_colors,
+ uint32_t* cooccurrence) {
+ uint32_t *lines, *line_top, *line_current, *line_tmp;
+ int x, y;
+ const uint32_t* src = pic->argb;
+ uint32_t prev_pix = ~src[0];
+ uint32_t prev_idx = 0u;
+ uint32_t idx_map[MAX_PALETTE_SIZE] = {0};
+ uint32_t palette_sorted[MAX_PALETTE_SIZE];
+ lines = (uint32_t*)WebPSafeMalloc(2 * pic->width, sizeof(*lines));
+ if (lines == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY;
+ line_top = &lines[0];
+ line_current = &lines[pic->width];
+ PrepareMapToPalette(palette, num_colors, palette_sorted, idx_map);
+ for (y = 0; y < pic->height; ++y) {
+ for (x = 0; x < pic->width; ++x) {
+ const uint32_t pix = src[x];
+ if (pix != prev_pix) {
+ prev_idx = idx_map[SearchColorNoIdx(palette_sorted, pix, num_colors)];
+ prev_pix = pix;
+ }
+ line_current[x] = prev_idx;
+ // 4-connectivity is what works best as mentioned in "On the relation
+ // between Memon's and the modified Zeng's palette reordering methods".
+ if (x > 0 && prev_idx != line_current[x - 1]) {
+ const uint32_t left_idx = line_current[x - 1];
+ ++cooccurrence[prev_idx * num_colors + left_idx];
+ ++cooccurrence[left_idx * num_colors + prev_idx];
+ }
+ if (y > 0 && prev_idx != line_top[x]) {
+ const uint32_t top_idx = line_top[x];
+ ++cooccurrence[prev_idx * num_colors + top_idx];
+ ++cooccurrence[top_idx * num_colors + prev_idx];
+ }
+ }
+ line_tmp = line_top;
+ line_top = line_current;
+ line_current = line_tmp;
+ src += pic->argb_stride;
+ }
+ WebPSafeFree(lines);
+ return VP8_ENC_OK;
+}
+
+struct Sum {
+ uint8_t index;
+ uint32_t sum;
+};
+
+// Implements the modified Zeng method from "A Survey on Palette Reordering
+// Methods for Improving the Compression of Color-Indexed Images" by Armando J.
+// Pinho and Antonio J. R. Neves.
+static WebPEncodingError PaletteSortModifiedZeng(
+ const WebPPicture* const pic, const uint32_t* const palette_sorted,
+ uint32_t num_colors, uint32_t* const palette) {
+ uint32_t i, j, ind;
+ uint8_t remapping[MAX_PALETTE_SIZE];
+ uint32_t* cooccurrence;
+ struct Sum sums[MAX_PALETTE_SIZE];
+ uint32_t first, last;
+ uint32_t num_sums;
+ // TODO(vrabaud) check whether one color images should use palette or not.
+ if (num_colors <= 1) return VP8_ENC_OK;
+ // Build the co-occurrence matrix.
+ cooccurrence =
+ (uint32_t*)WebPSafeCalloc(num_colors * num_colors, sizeof(*cooccurrence));
+ if (cooccurrence == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY;
+ if (CoOccurrenceBuild(pic, palette_sorted, num_colors, cooccurrence) !=
+ VP8_ENC_OK) {
+ WebPSafeFree(cooccurrence);
+ return VP8_ENC_ERROR_OUT_OF_MEMORY;
+ }
+
+ // Initialize the mapping list with the two best indices.
+ CoOccurrenceFindMax(cooccurrence, num_colors, &remapping[0], &remapping[1]);
+
+ // We need to append and prepend to the list of remapping. To this end, we
+ // actually define the next start/end of the list as indices in a vector (with
+ // a wrap around when the end is reached).
+ first = 0;
+ last = 1;
+ num_sums = num_colors - 2; // -2 because we know the first two values
+ if (num_sums > 0) {
+ // Initialize the sums with the first two remappings and find the best one
+ struct Sum* best_sum = &sums[0];
+ best_sum->index = 0u;
+ best_sum->sum = 0u;
+ for (i = 0, j = 0; i < num_colors; ++i) {
+ if (i == remapping[0] || i == remapping[1]) continue;
+ sums[j].index = i;
+ sums[j].sum = cooccurrence[i * num_colors + remapping[0]] +
+ cooccurrence[i * num_colors + remapping[1]];
+ if (sums[j].sum > best_sum->sum) best_sum = &sums[j];
+ ++j;
+ }
+
+ while (num_sums > 0) {
+ const uint8_t best_index = best_sum->index;
+ // Compute delta to know if we need to prepend or append the best index.
+ int32_t delta = 0;
+ const int32_t n = num_colors - num_sums;
+ for (ind = first, j = 0; (ind + j) % num_colors != last + 1; ++j) {
+ const uint16_t l_j = remapping[(ind + j) % num_colors];
+ delta += (n - 1 - 2 * (int32_t)j) *
+ (int32_t)cooccurrence[best_index * num_colors + l_j];
+ }
+ if (delta > 0) {
+ first = (first == 0) ? num_colors - 1 : first - 1;
+ remapping[first] = best_index;
+ } else {
+ ++last;
+ remapping[last] = best_index;
+ }
+ // Remove best_sum from sums.
+ *best_sum = sums[num_sums - 1];
+ --num_sums;
+ // Update all the sums and find the best one.
+ best_sum = &sums[0];
+ for (i = 0; i < num_sums; ++i) {
+ sums[i].sum += cooccurrence[best_index * num_colors + sums[i].index];
+ if (sums[i].sum > best_sum->sum) best_sum = &sums[i];
+ }
+ }
}
- *palette_size = num_colors;
- qsort(palette, num_colors, sizeof(*palette), PaletteCompareColorsForQsort);
- if (!low_effort && PaletteHasNonMonotonousDeltas(palette, num_colors)) {
- GreedyMinimizeDeltas(palette, num_colors);
+ assert((last + 1) % num_colors == first);
+ WebPSafeFree(cooccurrence);
+
+ // Re-map the palette.
+ for (i = 0; i < num_colors; ++i) {
+ palette[i] = palette_sorted[remapping[(first + i) % num_colors]];
}
- return 1;
+ return VP8_ENC_OK;
}
+// -----------------------------------------------------------------------------
+// Palette
+
// These five modes are evaluated and their respective entropy is computed.
typedef enum {
kDirect = 0,
@@ -144,10 +329,18 @@ typedef enum {
kSubGreen = 2,
kSpatialSubGreen = 3,
kPalette = 4,
- kNumEntropyIx = 5
+ kPaletteAndSpatial = 5,
+ kNumEntropyIx = 6
} EntropyIx;
typedef enum {
+ kSortedDefault = 0,
+ kMinimizeDelta = 1,
+ kModifiedZeng = 2,
+ kUnusedPalette = 3,
+} PaletteSorting;
+
+typedef enum {
kHistoAlpha = 0,
kHistoAlphaPred,
kHistoGreen,
@@ -354,14 +547,21 @@ static int GetTransformBits(int method, int histo_bits) {
}
// Set of parameters to be used in each iteration of the cruncher.
-#define CRUNCH_CONFIGS_LZ77_MAX 2
+#define CRUNCH_SUBCONFIGS_MAX 2
+typedef struct {
+ int lz77_;
+ int do_no_cache_;
+} CrunchSubConfig;
typedef struct {
int entropy_idx_;
- int lz77s_types_to_try_[CRUNCH_CONFIGS_LZ77_MAX];
- int lz77s_types_to_try_size_;
+ PaletteSorting palette_sorting_type_;
+ CrunchSubConfig sub_configs_[CRUNCH_SUBCONFIGS_MAX];
+ int sub_configs_size_;
} CrunchConfig;
-#define CRUNCH_CONFIGS_MAX kNumEntropyIx
+// +2 because we add a palette sorting configuration for kPalette and
+// kPaletteAndSpatial.
+#define CRUNCH_CONFIGS_MAX (kNumEntropyIx + 2)
static int EncoderAnalyze(VP8LEncoder* const enc,
CrunchConfig crunch_configs[CRUNCH_CONFIGS_MAX],
@@ -376,11 +576,20 @@ static int EncoderAnalyze(VP8LEncoder* const enc,
int i;
int use_palette;
int n_lz77s;
+ // If set to 0, analyze the cache with the computed cache value. If 1, also
+ // analyze with no-cache.
+ int do_no_cache = 0;
assert(pic != NULL && pic->argb != NULL);
- use_palette =
- AnalyzeAndCreatePalette(pic, low_effort,
- enc->palette_, &enc->palette_size_);
+ // Check whether a palette is possible.
+ enc->palette_size_ = WebPGetColorPalette(pic, enc->palette_sorted_);
+ use_palette = (enc->palette_size_ <= MAX_PALETTE_SIZE);
+ if (!use_palette) {
+ enc->palette_size_ = 0;
+ } else {
+ qsort(enc->palette_sorted_, enc->palette_size_,
+ sizeof(*enc->palette_sorted_), PaletteCompareColorsForQsort);
+ }
// Empirical bit sizes.
enc->histo_bits_ = GetHistoBits(method, use_palette,
@@ -390,6 +599,8 @@ static int EncoderAnalyze(VP8LEncoder* const enc,
if (low_effort) {
// AnalyzeEntropy is somewhat slow.
crunch_configs[0].entropy_idx_ = use_palette ? kPalette : kSpatialSubGreen;
+ crunch_configs[0].palette_sorting_type_ =
+ use_palette ? kSortedDefault : kUnusedPalette;
n_lz77s = 1;
*crunch_configs_size = 1;
} else {
@@ -402,29 +613,59 @@ static int EncoderAnalyze(VP8LEncoder* const enc,
return 0;
}
if (method == 6 && config->quality == 100) {
+ do_no_cache = 1;
// Go brute force on all transforms.
*crunch_configs_size = 0;
for (i = 0; i < kNumEntropyIx; ++i) {
- if (i != kPalette || use_palette) {
+ // We can only apply kPalette or kPaletteAndSpatial if we can indeed use
+ // a palette.
+ if ((i != kPalette && i != kPaletteAndSpatial) || use_palette) {
assert(*crunch_configs_size < CRUNCH_CONFIGS_MAX);
- crunch_configs[(*crunch_configs_size)++].entropy_idx_ = i;
+ crunch_configs[(*crunch_configs_size)].entropy_idx_ = i;
+ if (use_palette && (i == kPalette || i == kPaletteAndSpatial)) {
+ crunch_configs[(*crunch_configs_size)].palette_sorting_type_ =
+ kMinimizeDelta;
+ ++*crunch_configs_size;
+ // Also add modified Zeng's method.
+ crunch_configs[(*crunch_configs_size)].entropy_idx_ = i;
+ crunch_configs[(*crunch_configs_size)].palette_sorting_type_ =
+ kModifiedZeng;
+ } else {
+ crunch_configs[(*crunch_configs_size)].palette_sorting_type_ =
+ kUnusedPalette;
+ }
+ ++*crunch_configs_size;
}
}
} else {
// Only choose the guessed best transform.
*crunch_configs_size = 1;
crunch_configs[0].entropy_idx_ = min_entropy_ix;
+ crunch_configs[0].palette_sorting_type_ =
+ use_palette ? kMinimizeDelta : kUnusedPalette;
+ if (config->quality >= 75 && method == 5) {
+ // Test with and without color cache.
+ do_no_cache = 1;
+ // If we have a palette, also check in combination with spatial.
+ if (min_entropy_ix == kPalette) {
+ *crunch_configs_size = 2;
+ crunch_configs[1].entropy_idx_ = kPaletteAndSpatial;
+ crunch_configs[1].palette_sorting_type_ = kMinimizeDelta;
+ }
+ }
}
}
// Fill in the different LZ77s.
- assert(n_lz77s <= CRUNCH_CONFIGS_LZ77_MAX);
+ assert(n_lz77s <= CRUNCH_SUBCONFIGS_MAX);
for (i = 0; i < *crunch_configs_size; ++i) {
int j;
for (j = 0; j < n_lz77s; ++j) {
- crunch_configs[i].lz77s_types_to_try_[j] =
+ assert(j < CRUNCH_SUBCONFIGS_MAX);
+ crunch_configs[i].sub_configs_[j].lz77_ =
(j == 0) ? kLZ77Standard | kLZ77RLE : kLZ77Box;
+ crunch_configs[i].sub_configs_[j].do_no_cache_ = do_no_cache;
}
- crunch_configs[i].lz77s_types_to_try_size_ = n_lz77s;
+ crunch_configs[i].sub_configs_size_ = n_lz77s;
}
return 1;
}
@@ -440,7 +681,7 @@ static int EncoderInit(VP8LEncoder* const enc) {
int i;
if (!VP8LHashChainInit(&enc->hash_chain_, pix_cnt)) return 0;
- for (i = 0; i < 3; ++i) VP8LBackwardRefsInit(&enc->refs_[i], refs_block_size);
+ for (i = 0; i < 4; ++i) VP8LBackwardRefsInit(&enc->refs_[i], refs_block_size);
return 1;
}
@@ -769,13 +1010,10 @@ static WebPEncodingError StoreImageToBitMask(
}
// Special case of EncodeImageInternal() for cache-bits=0, histo_bits=31
-static WebPEncodingError EncodeImageNoHuffman(VP8LBitWriter* const bw,
- const uint32_t* const argb,
- VP8LHashChain* const hash_chain,
- VP8LBackwardRefs* const refs_tmp1,
- VP8LBackwardRefs* const refs_tmp2,
- int width, int height,
- int quality, int low_effort) {
+static WebPEncodingError EncodeImageNoHuffman(
+ VP8LBitWriter* const bw, const uint32_t* const argb,
+ VP8LHashChain* const hash_chain, VP8LBackwardRefs* const refs_array,
+ int width, int height, int quality, int low_effort) {
int i;
int max_tokens = 0;
WebPEncodingError err = VP8_ENC_OK;
@@ -798,13 +1036,11 @@ static WebPEncodingError EncodeImageNoHuffman(VP8LBitWriter* const bw,
err = VP8_ENC_ERROR_OUT_OF_MEMORY;
goto Error;
}
- refs = VP8LGetBackwardReferences(width, height, argb, quality, 0,
- kLZ77Standard | kLZ77RLE, &cache_bits,
- hash_chain, refs_tmp1, refs_tmp2);
- if (refs == NULL) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
- goto Error;
- }
+ err = VP8LGetBackwardReferences(
+ width, height, argb, quality, /*low_effort=*/0, kLZ77Standard | kLZ77RLE,
+ cache_bits, /*do_no_cache=*/0, hash_chain, refs_array, &cache_bits);
+ if (err != VP8_ENC_OK) goto Error;
+ refs = &refs_array[0];
histogram_image = VP8LAllocateHistogramSet(1, cache_bits);
if (histogram_image == NULL) {
err = VP8_ENC_ERROR_OUT_OF_MEMORY;
@@ -860,11 +1096,11 @@ static WebPEncodingError EncodeImageNoHuffman(VP8LBitWriter* const bw,
static WebPEncodingError EncodeImageInternal(
VP8LBitWriter* const bw, const uint32_t* const argb,
- VP8LHashChain* const hash_chain, VP8LBackwardRefs refs_array[3], int width,
+ VP8LHashChain* const hash_chain, VP8LBackwardRefs refs_array[4], int width,
int height, int quality, int low_effort, int use_cache,
const CrunchConfig* const config, int* cache_bits, int histogram_bits,
size_t init_byte_position, int* const hdr_size, int* const data_size) {
- WebPEncodingError err = VP8_ENC_OK;
+ WebPEncodingError err = VP8_ENC_ERROR_OUT_OF_MEMORY;
const uint32_t histogram_image_xysize =
VP8LSubSampleSize(width, histogram_bits) *
VP8LSubSampleSize(height, histogram_bits);
@@ -876,103 +1112,103 @@ static WebPEncodingError EncodeImageInternal(
3ULL * CODE_LENGTH_CODES, sizeof(*huff_tree));
HuffmanTreeToken* tokens = NULL;
HuffmanTreeCode* huffman_codes = NULL;
- VP8LBackwardRefs* refs_best;
- VP8LBackwardRefs* refs_tmp;
uint16_t* const histogram_symbols =
(uint16_t*)WebPSafeMalloc(histogram_image_xysize,
sizeof(*histogram_symbols));
- int lz77s_idx;
+ int sub_configs_idx;
+ int cache_bits_init, write_histogram_image;
VP8LBitWriter bw_init = *bw, bw_best;
int hdr_size_tmp;
+ VP8LHashChain hash_chain_histogram; // histogram image hash chain
+ size_t bw_size_best = ~(size_t)0;
assert(histogram_bits >= MIN_HUFFMAN_BITS);
assert(histogram_bits <= MAX_HUFFMAN_BITS);
assert(hdr_size != NULL);
assert(data_size != NULL);
- if (histogram_symbols == NULL) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ // Make sure we can allocate the different objects.
+ memset(&hash_chain_histogram, 0, sizeof(hash_chain_histogram));
+ if (huff_tree == NULL || histogram_symbols == NULL ||
+ !VP8LHashChainInit(&hash_chain_histogram, histogram_image_xysize) ||
+ !VP8LHashChainFill(hash_chain, quality, argb, width, height,
+ low_effort)) {
goto Error;
}
-
if (use_cache) {
// If the value is different from zero, it has been set during the
// palette analysis.
- if (*cache_bits == 0) *cache_bits = MAX_COLOR_CACHE_BITS;
+ cache_bits_init = (*cache_bits == 0) ? MAX_COLOR_CACHE_BITS : *cache_bits;
} else {
- *cache_bits = 0;
+ cache_bits_init = 0;
}
- // 'best_refs' is the reference to the best backward refs and points to one
- // of refs_array[0] or refs_array[1].
- // Calculate backward references from ARGB image.
- if (huff_tree == NULL ||
- !VP8LHashChainFill(hash_chain, quality, argb, width, height,
- low_effort) ||
- !VP8LBitWriterInit(&bw_best, 0) ||
- (config->lz77s_types_to_try_size_ > 1 &&
+ // If several iterations will happen, clone into bw_best.
+ if (!VP8LBitWriterInit(&bw_best, 0) ||
+ ((config->sub_configs_size_ > 1 ||
+ config->sub_configs_[0].do_no_cache_) &&
!VP8LBitWriterClone(bw, &bw_best))) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
goto Error;
}
- for (lz77s_idx = 0; lz77s_idx < config->lz77s_types_to_try_size_;
- ++lz77s_idx) {
- refs_best = VP8LGetBackwardReferences(
- width, height, argb, quality, low_effort,
- config->lz77s_types_to_try_[lz77s_idx], cache_bits, hash_chain,
- &refs_array[0], &refs_array[1]);
- if (refs_best == NULL) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
- goto Error;
- }
- // Keep the best references aside and use the other element from the first
- // two as a temporary for later usage.
- refs_tmp = &refs_array[refs_best == &refs_array[0] ? 1 : 0];
-
- histogram_image =
- VP8LAllocateHistogramSet(histogram_image_xysize, *cache_bits);
- tmp_histo = VP8LAllocateHistogram(*cache_bits);
- if (histogram_image == NULL || tmp_histo == NULL) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
- goto Error;
- }
-
- // Build histogram image and symbols from backward references.
- if (!VP8LGetHistoImageSymbols(width, height, refs_best, quality, low_effort,
- histogram_bits, *cache_bits, histogram_image,
- tmp_histo, histogram_symbols)) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
- goto Error;
- }
- // Create Huffman bit lengths and codes for each histogram image.
- histogram_image_size = histogram_image->size;
- bit_array_size = 5 * histogram_image_size;
- huffman_codes = (HuffmanTreeCode*)WebPSafeCalloc(bit_array_size,
- sizeof(*huffman_codes));
- // Note: some histogram_image entries may point to tmp_histos[], so the
- // latter need to outlive the following call to GetHuffBitLengthsAndCodes().
- if (huffman_codes == NULL ||
- !GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
- goto Error;
- }
- // Free combined histograms.
- VP8LFreeHistogramSet(histogram_image);
- histogram_image = NULL;
-
- // Free scratch histograms.
- VP8LFreeHistogram(tmp_histo);
- tmp_histo = NULL;
+ for (sub_configs_idx = 0; sub_configs_idx < config->sub_configs_size_;
+ ++sub_configs_idx) {
+ const CrunchSubConfig* const sub_config =
+ &config->sub_configs_[sub_configs_idx];
+ int cache_bits_best, i_cache;
+ err = VP8LGetBackwardReferences(width, height, argb, quality, low_effort,
+ sub_config->lz77_, cache_bits_init,
+ sub_config->do_no_cache_, hash_chain,
+ &refs_array[0], &cache_bits_best);
+ if (err != VP8_ENC_OK) goto Error;
- // Color Cache parameters.
- if (*cache_bits > 0) {
- VP8LPutBits(bw, 1, 1);
- VP8LPutBits(bw, *cache_bits, 4);
- } else {
- VP8LPutBits(bw, 0, 1);
- }
+ for (i_cache = 0; i_cache < (sub_config->do_no_cache_ ? 2 : 1); ++i_cache) {
+ const int cache_bits_tmp = (i_cache == 0) ? cache_bits_best : 0;
+ // Speed-up: no need to study the no-cache case if it was already studied
+ // in i_cache == 0.
+ if (i_cache == 1 && cache_bits_best == 0) break;
+
+ // Reset the bit writer for this iteration.
+ VP8LBitWriterReset(&bw_init, bw);
+
+ // Build histogram image and symbols from backward references.
+ histogram_image =
+ VP8LAllocateHistogramSet(histogram_image_xysize, cache_bits_tmp);
+ tmp_histo = VP8LAllocateHistogram(cache_bits_tmp);
+ if (histogram_image == NULL || tmp_histo == NULL ||
+ !VP8LGetHistoImageSymbols(width, height, &refs_array[i_cache],
+ quality, low_effort, histogram_bits,
+ cache_bits_tmp, histogram_image, tmp_histo,
+ histogram_symbols)) {
+ goto Error;
+ }
+ // Create Huffman bit lengths and codes for each histogram image.
+ histogram_image_size = histogram_image->size;
+ bit_array_size = 5 * histogram_image_size;
+ huffman_codes = (HuffmanTreeCode*)WebPSafeCalloc(bit_array_size,
+ sizeof(*huffman_codes));
+ // Note: some histogram_image entries may point to tmp_histos[], so the
+ // latter need to outlive the following call to
+ // GetHuffBitLengthsAndCodes().
+ if (huffman_codes == NULL ||
+ !GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) {
+ goto Error;
+ }
+ // Free combined histograms.
+ VP8LFreeHistogramSet(histogram_image);
+ histogram_image = NULL;
+
+ // Free scratch histograms.
+ VP8LFreeHistogram(tmp_histo);
+ tmp_histo = NULL;
+
+ // Color Cache parameters.
+ if (cache_bits_tmp > 0) {
+ VP8LPutBits(bw, 1, 1);
+ VP8LPutBits(bw, cache_bits_tmp, 4);
+ } else {
+ VP8LPutBits(bw, 0, 1);
+ }
- // Huffman image + meta huffman.
- {
- const int write_histogram_image = (histogram_image_size > 1);
+ // Huffman image + meta huffman.
+ write_histogram_image = (histogram_image_size > 1);
VP8LPutBits(bw, write_histogram_image, 1);
if (write_histogram_image) {
uint32_t* const histogram_argb =
@@ -980,10 +1216,7 @@ static WebPEncodingError EncodeImageInternal(
sizeof(*histogram_argb));
int max_index = 0;
uint32_t i;
- if (histogram_argb == NULL) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
- goto Error;
- }
+ if (histogram_argb == NULL) goto Error;
for (i = 0; i < histogram_image_xysize; ++i) {
const int symbol_index = histogram_symbols[i] & 0xffff;
histogram_argb[i] = (symbol_index << 8);
@@ -995,65 +1228,64 @@ static WebPEncodingError EncodeImageInternal(
VP8LPutBits(bw, histogram_bits - 2, 3);
err = EncodeImageNoHuffman(
- bw, histogram_argb, hash_chain, refs_tmp, &refs_array[2],
+ bw, histogram_argb, &hash_chain_histogram, &refs_array[2],
VP8LSubSampleSize(width, histogram_bits),
VP8LSubSampleSize(height, histogram_bits), quality, low_effort);
WebPSafeFree(histogram_argb);
if (err != VP8_ENC_OK) goto Error;
}
- }
- // Store Huffman codes.
- {
- int i;
- int max_tokens = 0;
- // Find maximum number of symbols for the huffman tree-set.
- for (i = 0; i < 5 * histogram_image_size; ++i) {
- HuffmanTreeCode* const codes = &huffman_codes[i];
- if (max_tokens < codes->num_symbols) {
- max_tokens = codes->num_symbols;
+ // Store Huffman codes.
+ {
+ int i;
+ int max_tokens = 0;
+ // Find maximum number of symbols for the huffman tree-set.
+ for (i = 0; i < 5 * histogram_image_size; ++i) {
+ HuffmanTreeCode* const codes = &huffman_codes[i];
+ if (max_tokens < codes->num_symbols) {
+ max_tokens = codes->num_symbols;
+ }
+ }
+ tokens = (HuffmanTreeToken*)WebPSafeMalloc(max_tokens, sizeof(*tokens));
+ if (tokens == NULL) goto Error;
+ for (i = 0; i < 5 * histogram_image_size; ++i) {
+ HuffmanTreeCode* const codes = &huffman_codes[i];
+ StoreHuffmanCode(bw, huff_tree, tokens, codes);
+ ClearHuffmanTreeIfOnlyOneSymbol(codes);
}
}
- tokens = (HuffmanTreeToken*)WebPSafeMalloc(max_tokens, sizeof(*tokens));
- if (tokens == NULL) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
- goto Error;
+ // Store actual literals.
+ hdr_size_tmp = (int)(VP8LBitWriterNumBytes(bw) - init_byte_position);
+ err = StoreImageToBitMask(bw, width, histogram_bits, &refs_array[i_cache],
+ histogram_symbols, huffman_codes);
+ if (err != VP8_ENC_OK) goto Error;
+ // Keep track of the smallest image so far.
+ if (VP8LBitWriterNumBytes(bw) < bw_size_best) {
+ bw_size_best = VP8LBitWriterNumBytes(bw);
+ *cache_bits = cache_bits_tmp;
+ *hdr_size = hdr_size_tmp;
+ *data_size =
+ (int)(VP8LBitWriterNumBytes(bw) - init_byte_position - *hdr_size);
+ VP8LBitWriterSwap(bw, &bw_best);
}
- for (i = 0; i < 5 * histogram_image_size; ++i) {
- HuffmanTreeCode* const codes = &huffman_codes[i];
- StoreHuffmanCode(bw, huff_tree, tokens, codes);
- ClearHuffmanTreeIfOnlyOneSymbol(codes);
+ WebPSafeFree(tokens);
+ tokens = NULL;
+ if (huffman_codes != NULL) {
+ WebPSafeFree(huffman_codes->codes);
+ WebPSafeFree(huffman_codes);
+ huffman_codes = NULL;
}
}
- // Store actual literals.
- hdr_size_tmp = (int)(VP8LBitWriterNumBytes(bw) - init_byte_position);
- err = StoreImageToBitMask(bw, width, histogram_bits, refs_best,
- histogram_symbols, huffman_codes);
- // Keep track of the smallest image so far.
- if (lz77s_idx == 0 ||
- VP8LBitWriterNumBytes(bw) < VP8LBitWriterNumBytes(&bw_best)) {
- *hdr_size = hdr_size_tmp;
- *data_size =
- (int)(VP8LBitWriterNumBytes(bw) - init_byte_position - *hdr_size);
- VP8LBitWriterSwap(bw, &bw_best);
- }
- // Reset the bit writer for the following iteration if any.
- if (config->lz77s_types_to_try_size_ > 1) VP8LBitWriterReset(&bw_init, bw);
- WebPSafeFree(tokens);
- tokens = NULL;
- if (huffman_codes != NULL) {
- WebPSafeFree(huffman_codes->codes);
- WebPSafeFree(huffman_codes);
- huffman_codes = NULL;
- }
}
VP8LBitWriterSwap(bw, &bw_best);
+ err = VP8_ENC_OK;
Error:
WebPSafeFree(tokens);
WebPSafeFree(huff_tree);
VP8LFreeHistogramSet(histogram_image);
VP8LFreeHistogram(tmp_histo);
+ VP8LHashChainClear(&hash_chain_histogram);
if (huffman_codes != NULL) {
WebPSafeFree(huffman_codes->codes);
WebPSafeFree(huffman_codes);
@@ -1095,8 +1327,7 @@ static WebPEncodingError ApplyPredictFilter(const VP8LEncoder* const enc,
VP8LPutBits(bw, pred_bits - 2, 3);
return EncodeImageNoHuffman(
bw, enc->transform_data_, (VP8LHashChain*)&enc->hash_chain_,
- (VP8LBackwardRefs*)&enc->refs_[0], // cast const away
- (VP8LBackwardRefs*)&enc->refs_[1], transform_width, transform_height,
+ (VP8LBackwardRefs*)&enc->refs_[0], transform_width, transform_height,
quality, low_effort);
}
@@ -1116,8 +1347,7 @@ static WebPEncodingError ApplyCrossColorFilter(const VP8LEncoder* const enc,
VP8LPutBits(bw, ccolor_transform_bits - 2, 3);
return EncodeImageNoHuffman(
bw, enc->transform_data_, (VP8LHashChain*)&enc->hash_chain_,
- (VP8LBackwardRefs*)&enc->refs_[0], // cast const away
- (VP8LBackwardRefs*)&enc->refs_[1], transform_width, transform_height,
+ (VP8LBackwardRefs*)&enc->refs_[0], transform_width, transform_height,
quality, low_effort);
}
@@ -1272,22 +1502,6 @@ static WebPEncodingError MakeInputImageCopy(VP8LEncoder* const enc) {
// -----------------------------------------------------------------------------
-static WEBP_INLINE int SearchColorNoIdx(const uint32_t sorted[], uint32_t color,
- int hi) {
- int low = 0;
- if (sorted[low] == color) return low; // loop invariant: sorted[low] != color
- while (1) {
- const int mid = (low + hi) >> 1;
- if (sorted[mid] == color) {
- return mid;
- } else if (sorted[mid] < color) {
- low = mid;
- } else {
- hi = mid;
- }
- }
-}
-
#define APPLY_PALETTE_GREEDY_MAX 4
static WEBP_INLINE uint32_t SearchColorGreedy(const uint32_t palette[],
@@ -1322,17 +1536,6 @@ static WEBP_INLINE uint32_t ApplyPaletteHash2(uint32_t color) {
(32 - PALETTE_INV_SIZE_BITS);
}
-// Sort palette in increasing order and prepare an inverse mapping array.
-static void PrepareMapToPalette(const uint32_t palette[], int num_colors,
- uint32_t sorted[], uint32_t idx_map[]) {
- int i;
- memcpy(sorted, palette, num_colors * sizeof(*sorted));
- qsort(sorted, num_colors, sizeof(*sorted), PaletteCompareColorsForQsort);
- for (i = 0; i < num_colors; ++i) {
- idx_map[SearchColorNoIdx(sorted, palette[i], num_colors)] = i;
- }
-}
-
// Use 1 pixel cache for ARGB pixels.
#define APPLY_PALETTE_FOR(COLOR_INDEX) do { \
uint32_t prev_pix = palette[0]; \
@@ -1464,8 +1667,8 @@ static WebPEncodingError EncodePalette(VP8LBitWriter* const bw, int low_effort,
}
tmp_palette[0] = palette[0];
return EncodeImageNoHuffman(bw, tmp_palette, &enc->hash_chain_,
- &enc->refs_[0], &enc->refs_[1], palette_size, 1,
- 20 /* quality */, low_effort);
+ &enc->refs_[0], palette_size, 1, /*quality=*/20,
+ low_effort);
}
// -----------------------------------------------------------------------------
@@ -1491,7 +1694,7 @@ static void VP8LEncoderDelete(VP8LEncoder* enc) {
if (enc != NULL) {
int i;
VP8LHashChainClear(&enc->hash_chain_);
- for (i = 0; i < 3; ++i) VP8LBackwardRefsClear(&enc->refs_[i]);
+ for (i = 0; i < 4; ++i) VP8LBackwardRefsClear(&enc->refs_[i]);
ClearTransformBuffer(enc);
WebPSafeFree(enc);
}
@@ -1541,7 +1744,7 @@ static int EncodeStreamHook(void* input, void* data2) {
int data_size = 0;
int use_delta_palette = 0;
int idx;
- size_t best_size = 0;
+ size_t best_size = ~(size_t)0;
VP8LBitWriter bw_init = *bw, bw_best;
(void)data2;
@@ -1553,12 +1756,15 @@ static int EncodeStreamHook(void* input, void* data2) {
for (idx = 0; idx < num_crunch_configs; ++idx) {
const int entropy_idx = crunch_configs[idx].entropy_idx_;
- enc->use_palette_ = (entropy_idx == kPalette);
+ enc->use_palette_ =
+ (entropy_idx == kPalette) || (entropy_idx == kPaletteAndSpatial);
enc->use_subtract_green_ =
(entropy_idx == kSubGreen) || (entropy_idx == kSpatialSubGreen);
- enc->use_predict_ =
- (entropy_idx == kSpatial) || (entropy_idx == kSpatialSubGreen);
- if (low_effort) {
+ enc->use_predict_ = (entropy_idx == kSpatial) ||
+ (entropy_idx == kSpatialSubGreen) ||
+ (entropy_idx == kPaletteAndSpatial);
+ // When using a palette, R/B==0, hence no need to test for cross-color.
+ if (low_effort || enc->use_palette_) {
enc->use_cross_color_ = 0;
} else {
enc->use_cross_color_ = red_and_blue_always_zero ? 0 : enc->use_predict_;
@@ -1590,6 +1796,19 @@ static int EncodeStreamHook(void* input, void* data2) {
// Encode palette
if (enc->use_palette_) {
+ if (crunch_configs[idx].palette_sorting_type_ == kSortedDefault) {
+ // Nothing to do, we have already sorted the palette.
+ memcpy(enc->palette_, enc->palette_sorted_,
+ enc->palette_size_ * sizeof(*enc->palette_));
+ } else if (crunch_configs[idx].palette_sorting_type_ == kMinimizeDelta) {
+ PaletteSortMinimizeDeltas(enc->palette_sorted_, enc->palette_size_,
+ enc->palette_);
+ } else {
+ assert(crunch_configs[idx].palette_sorting_type_ == kModifiedZeng);
+ err = PaletteSortModifiedZeng(enc->pic_, enc->palette_sorted_,
+ enc->palette_size_, enc->palette_);
+ if (err != VP8_ENC_OK) goto Error;
+ }
err = EncodePalette(bw, low_effort, enc);
if (err != VP8_ENC_OK) goto Error;
err = MapImageFromPalette(enc, use_delta_palette);
@@ -1640,7 +1859,7 @@ static int EncodeStreamHook(void* input, void* data2) {
if (err != VP8_ENC_OK) goto Error;
// If we are better than what we already have.
- if (idx == 0 || VP8LBitWriterNumBytes(bw) < best_size) {
+ if (VP8LBitWriterNumBytes(bw) < best_size) {
best_size = VP8LBitWriterNumBytes(bw);
// Store the BitWriter.
VP8LBitWriterSwap(bw, &bw_best);
@@ -1754,6 +1973,8 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
enc_side->palette_size_ = enc_main->palette_size_;
memcpy(enc_side->palette_, enc_main->palette_,
sizeof(enc_main->palette_));
+ memcpy(enc_side->palette_sorted_, enc_main->palette_sorted_,
+ sizeof(enc_main->palette_sorted_));
param->enc_ = enc_side;
}
// Create the workers.
@@ -1816,7 +2037,7 @@ Error:
}
#undef CRUNCH_CONFIGS_MAX
-#undef CRUNCH_CONFIGS_LZ77_MAX
+#undef CRUNCH_SUBCONFIGS_MAX
int VP8LEncodeImage(const WebPConfig* const config,
const WebPPicture* const picture) {
diff --git a/thirdparty/libwebp/src/enc/vp8li_enc.h b/thirdparty/libwebp/src/enc/vp8li_enc.h
index d2d0fc509c..00de48946c 100644
--- a/thirdparty/libwebp/src/enc/vp8li_enc.h
+++ b/thirdparty/libwebp/src/enc/vp8li_enc.h
@@ -69,9 +69,11 @@ typedef struct {
int use_palette_;
int palette_size_;
uint32_t palette_[MAX_PALETTE_SIZE];
+ // Sorted version of palette_ for cache purposes.
+ uint32_t palette_sorted_[MAX_PALETTE_SIZE];
// Some 'scratch' (potentially large) objects.
- struct VP8LBackwardRefs refs_[3]; // Backward Refs array for temporaries.
+ struct VP8LBackwardRefs refs_[4]; // Backward Refs array for temporaries.
VP8LHashChain hash_chain_; // HashChain data for constructing
// backward references.
} VP8LEncoder;
diff --git a/thirdparty/libwebp/src/enc/webp_enc.c b/thirdparty/libwebp/src/enc/webp_enc.c
index 9f4b10c26c..ce2db2e94b 100644
--- a/thirdparty/libwebp/src/enc/webp_enc.c
+++ b/thirdparty/libwebp/src/enc/webp_enc.c
@@ -400,7 +400,7 @@ int WebPEncode(const WebPConfig* config, WebPPicture* pic) {
}
if (!config->exact) {
- WebPCleanupTransparentAreaLossless(pic);
+ WebPReplaceTransparentPixels(pic, 0x000000);
}
ok = VP8LEncodeImage(config, pic); // Sets pic->error in case of problem.
diff --git a/thirdparty/libwebp/src/mux/anim_encode.c b/thirdparty/libwebp/src/mux/anim_encode.c
index 7be99068f6..7078d9ae6b 100644
--- a/thirdparty/libwebp/src/mux/anim_encode.c
+++ b/thirdparty/libwebp/src/mux/anim_encode.c
@@ -248,9 +248,6 @@ WebPAnimEncoder* WebPAnimEncoderNewInternal(
enc = (WebPAnimEncoder*)WebPSafeCalloc(1, sizeof(*enc));
if (enc == NULL) return NULL;
- // sanity inits, so we can call WebPAnimEncoderDelete():
- enc->encoded_frames_ = NULL;
- enc->mux_ = NULL;
MarkNoError(enc);
// Dimensions and options.
@@ -421,7 +418,7 @@ static void MinimizeChangeRectangle(const WebPPicture* const src,
const int max_allowed_diff_lossy = QualityToMaxDiff(quality);
const int max_allowed_diff = is_lossless ? 0 : max_allowed_diff_lossy;
- // Sanity checks.
+ // Assumption/correctness checks.
assert(src->width == dst->width && src->height == dst->height);
assert(rect->x_offset_ + rect->width_ <= dst->width);
assert(rect->y_offset_ + rect->height_ <= dst->height);
@@ -949,7 +946,8 @@ static int IncreasePreviousDuration(WebPAnimEncoder* const enc, int duration) {
int new_duration;
assert(enc->count_ >= 1);
- assert(prev_enc_frame->sub_frame_.duration ==
+ assert(!prev_enc_frame->is_key_frame_ ||
+ prev_enc_frame->sub_frame_.duration ==
prev_enc_frame->key_frame_.duration);
assert(prev_enc_frame->sub_frame_.duration ==
(prev_enc_frame->sub_frame_.duration & (MAX_DURATION - 1)));
@@ -966,7 +964,7 @@ static int IncreasePreviousDuration(WebPAnimEncoder* const enc, int duration) {
0x10, 0x88, 0x88, 0x08
};
const WebPData lossless_1x1 = {
- lossless_1x1_bytes, sizeof(lossless_1x1_bytes)
+ lossless_1x1_bytes, sizeof(lossless_1x1_bytes)
};
const uint8_t lossy_1x1_bytes[] = {
0x52, 0x49, 0x46, 0x46, 0x40, 0x00, 0x00, 0x00, 0x57, 0x45, 0x42, 0x50,
@@ -1358,6 +1356,12 @@ int WebPAnimEncoderAdd(WebPAnimEncoder* enc, WebPPicture* frame, int timestamp,
if (!IncreasePreviousDuration(enc, (int)prev_frame_duration)) {
return 0;
}
+ // IncreasePreviousDuration() may add a frame to avoid exceeding
+ // MAX_DURATION which could cause CacheFrame() to over read encoded_frames_
+ // before the next flush.
+ if (enc->count_ == enc->size_ && !FlushFrames(enc)) {
+ return 0;
+ }
} else {
enc->first_timestamp_ = timestamp;
}
diff --git a/thirdparty/libwebp/src/mux/muxedit.c b/thirdparty/libwebp/src/mux/muxedit.c
index ccf14b2a0c..02c3edecd7 100644
--- a/thirdparty/libwebp/src/mux/muxedit.c
+++ b/thirdparty/libwebp/src/mux/muxedit.c
@@ -235,7 +235,6 @@ WebPMuxError WebPMuxSetImage(WebPMux* mux, const WebPData* bitstream,
WebPMuxImage wpi;
WebPMuxError err;
- // Sanity checks.
if (mux == NULL || bitstream == NULL || bitstream->bytes == NULL ||
bitstream->size > MAX_CHUNK_PAYLOAD) {
return WEBP_MUX_INVALID_ARGUMENT;
@@ -267,7 +266,6 @@ WebPMuxError WebPMuxPushFrame(WebPMux* mux, const WebPMuxFrameInfo* info,
WebPMuxImage wpi;
WebPMuxError err;
- // Sanity checks.
if (mux == NULL || info == NULL) return WEBP_MUX_INVALID_ARGUMENT;
if (info->id != WEBP_CHUNK_ANMF) return WEBP_MUX_INVALID_ARGUMENT;
diff --git a/thirdparty/libwebp/src/mux/muxi.h b/thirdparty/libwebp/src/mux/muxi.h
index ad3e1bdb97..330da66754 100644
--- a/thirdparty/libwebp/src/mux/muxi.h
+++ b/thirdparty/libwebp/src/mux/muxi.h
@@ -28,8 +28,8 @@ extern "C" {
// Defines and constants.
#define MUX_MAJ_VERSION 1
-#define MUX_MIN_VERSION 1
-#define MUX_REV_VERSION 0
+#define MUX_MIN_VERSION 2
+#define MUX_REV_VERSION 1
// Chunk object.
typedef struct WebPChunk WebPChunk;
diff --git a/thirdparty/libwebp/src/mux/muxread.c b/thirdparty/libwebp/src/mux/muxread.c
index ae3b876bc5..80050396e1 100644
--- a/thirdparty/libwebp/src/mux/muxread.c
+++ b/thirdparty/libwebp/src/mux/muxread.c
@@ -56,7 +56,7 @@ static WebPMuxError ChunkVerifyAndAssign(WebPChunk* chunk,
uint32_t chunk_size;
WebPData chunk_data;
- // Sanity checks.
+ // Correctness checks.
if (data_size < CHUNK_HEADER_SIZE) return WEBP_MUX_NOT_ENOUGH_DATA;
chunk_size = GetLE32(data + TAG_SIZE);
if (chunk_size > MAX_CHUNK_PAYLOAD) return WEBP_MUX_BAD_DATA;
@@ -155,7 +155,6 @@ static int MuxImageParse(const WebPChunk* const chunk, int copy_data,
break;
default:
goto Fail;
- break;
}
subchunk_size = ChunkDiskSize(&subchunk);
bytes += subchunk_size;
@@ -187,7 +186,6 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data,
WebPChunk** chunk_list_ends[WEBP_CHUNK_NIL + 1] = { NULL };
ChunkInit(&chunk);
- // Sanity checks.
if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_MUX_ABI_VERSION)) {
return NULL; // version mismatch
}
@@ -264,7 +262,6 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data,
if (!MuxImageParse(&chunk, copy_data, wpi)) goto Err;
ChunkRelease(&chunk);
goto PushImage;
- break;
default: // A non-image chunk.
if (wpi->is_partial_) goto Err; // Encountered a non-image chunk before
// getting all chunks of an image.
@@ -483,7 +480,6 @@ WebPMuxError WebPMuxGetFrame(
WebPMuxError err;
WebPMuxImage* wpi;
- // Sanity checks.
if (mux == NULL || frame == NULL) {
return WEBP_MUX_INVALID_ARGUMENT;
}
diff --git a/thirdparty/libwebp/src/utils/bit_reader_inl_utils.h b/thirdparty/libwebp/src/utils/bit_reader_inl_utils.h
index 46b3880706..404b9a6d8c 100644
--- a/thirdparty/libwebp/src/utils/bit_reader_inl_utils.h
+++ b/thirdparty/libwebp/src/utils/bit_reader_inl_utils.h
@@ -55,7 +55,7 @@ void VP8LoadFinalBytes(VP8BitReader* const br);
// makes sure br->value_ has at least BITS bits worth of data
static WEBP_UBSAN_IGNORE_UNDEF WEBP_INLINE
-void VP8LoadNewBytes(VP8BitReader* const br) {
+void VP8LoadNewBytes(VP8BitReader* WEBP_RESTRICT const br) {
assert(br != NULL && br->buf_ != NULL);
// Read 'BITS' bits at a time if possible.
if (br->buf_ < br->buf_max_) {
@@ -104,7 +104,7 @@ void VP8LoadNewBytes(VP8BitReader* const br) {
}
// Read a bit with proba 'prob'. Speed-critical function!
-static WEBP_INLINE int VP8GetBit(VP8BitReader* const br,
+static WEBP_INLINE int VP8GetBit(VP8BitReader* WEBP_RESTRICT const br,
int prob, const char label[]) {
// Don't move this declaration! It makes a big speed difference to store
// 'range' *before* calling VP8LoadNewBytes(), even if this function doesn't
@@ -137,7 +137,8 @@ static WEBP_INLINE int VP8GetBit(VP8BitReader* const br,
// simplified version of VP8GetBit() for prob=0x80 (note shift is always 1 here)
static WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW WEBP_INLINE
-int VP8GetSigned(VP8BitReader* const br, int v, const char label[]) {
+int VP8GetSigned(VP8BitReader* WEBP_RESTRICT const br, int v,
+ const char label[]) {
if (br->bits_ < 0) {
VP8LoadNewBytes(br);
}
@@ -155,7 +156,7 @@ int VP8GetSigned(VP8BitReader* const br, int v, const char label[]) {
}
}
-static WEBP_INLINE int VP8GetBitAlt(VP8BitReader* const br,
+static WEBP_INLINE int VP8GetBitAlt(VP8BitReader* WEBP_RESTRICT const br,
int prob, const char label[]) {
// Don't move this declaration! It makes a big speed difference to store
// 'range' *before* calling VP8LoadNewBytes(), even if this function doesn't
diff --git a/thirdparty/libwebp/src/utils/bit_reader_utils.c b/thirdparty/libwebp/src/utils/bit_reader_utils.c
index 60271c0ae0..857cd60988 100644
--- a/thirdparty/libwebp/src/utils/bit_reader_utils.c
+++ b/thirdparty/libwebp/src/utils/bit_reader_utils.c
@@ -41,14 +41,7 @@ void VP8InitBitReader(VP8BitReader* const br,
br->bits_ = -8; // to load the very first 8bits
br->eof_ = 0;
VP8BitReaderSetBuffer(br, start, size);
-// -- GODOT -- begin
-#ifdef JAVASCRIPT_ENABLED // html5 required aligned reads
- while(((uintptr_t)br->buf_ & 1) != 0 && !br->eof_)
- VP8LoadFinalBytes(br);
-#else
VP8LoadNewBytes(br);
-#endif
-// -- GODOT -- end
}
void VP8RemapBitReader(VP8BitReader* const br, ptrdiff_t offset) {
diff --git a/thirdparty/libwebp/src/utils/bit_reader_utils.h b/thirdparty/libwebp/src/utils/bit_reader_utils.h
index 199dacf224..e64156e318 100644
--- a/thirdparty/libwebp/src/utils/bit_reader_utils.h
+++ b/thirdparty/libwebp/src/utils/bit_reader_utils.h
@@ -58,12 +58,6 @@ extern "C" {
// BITS can be any multiple of 8 from 8 to 56 (inclusive).
// Pick values that fit natural register size.
-// -- GODOT -- start
-#ifdef JAVASCRIPT_ENABLED
-#define BITS 16
-#else
-// -- GODOT -- end
-
#if defined(__i386__) || defined(_M_IX86) // x86 32bit
#define BITS 24
#elif defined(__x86_64__) || defined(_M_X64) // x86 64bit
@@ -78,10 +72,6 @@ extern "C" {
#define BITS 24
#endif
-// -- GODOT -- start
-#endif
-// -- GODOT -- end
-
//------------------------------------------------------------------------------
// Derived types and constants:
// bit_t = natural register type for storing 'value_' (which is BITS+8 bits)
diff --git a/thirdparty/libwebp/src/utils/bit_writer_utils.c b/thirdparty/libwebp/src/utils/bit_writer_utils.c
index bef0e31ca5..2f408508f1 100644
--- a/thirdparty/libwebp/src/utils/bit_writer_utils.c
+++ b/thirdparty/libwebp/src/utils/bit_writer_utils.c
@@ -278,7 +278,7 @@ void VP8LPutBitsFlushBits(VP8LBitWriter* const bw) {
// If needed, make some room by flushing some bits out.
if (bw->cur_ + VP8L_WRITER_BYTES > bw->end_) {
const uint64_t extra_size = (bw->end_ - bw->buf_) + MIN_EXTRA_SIZE;
- if (extra_size != (size_t)extra_size ||
+ if (!CheckSizeOverflow(extra_size) ||
!VP8LBitWriterResize(bw, (size_t)extra_size)) {
bw->cur_ = bw->buf_;
bw->error_ = 1;
@@ -314,7 +314,7 @@ void VP8LPutBitsInternal(VP8LBitWriter* const bw, uint32_t bits, int n_bits) {
while (used >= VP8L_WRITER_BITS) {
if (bw->cur_ + VP8L_WRITER_BYTES > bw->end_) {
const uint64_t extra_size = (bw->end_ - bw->buf_) + MIN_EXTRA_SIZE;
- if (extra_size != (size_t)extra_size ||
+ if (!CheckSizeOverflow(extra_size) ||
!VP8LBitWriterResize(bw, (size_t)extra_size)) {
bw->cur_ = bw->buf_;
bw->error_ = 1;
diff --git a/thirdparty/libwebp/src/utils/color_cache_utils.c b/thirdparty/libwebp/src/utils/color_cache_utils.c
index b09f538e8b..7b5222b6e5 100644
--- a/thirdparty/libwebp/src/utils/color_cache_utils.c
+++ b/thirdparty/libwebp/src/utils/color_cache_utils.c
@@ -20,22 +20,22 @@
//------------------------------------------------------------------------------
// VP8LColorCache.
-int VP8LColorCacheInit(VP8LColorCache* const cc, int hash_bits) {
+int VP8LColorCacheInit(VP8LColorCache* const color_cache, int hash_bits) {
const int hash_size = 1 << hash_bits;
- assert(cc != NULL);
+ assert(color_cache != NULL);
assert(hash_bits > 0);
- cc->colors_ = (uint32_t*)WebPSafeCalloc((uint64_t)hash_size,
- sizeof(*cc->colors_));
- if (cc->colors_ == NULL) return 0;
- cc->hash_shift_ = 32 - hash_bits;
- cc->hash_bits_ = hash_bits;
+ color_cache->colors_ = (uint32_t*)WebPSafeCalloc(
+ (uint64_t)hash_size, sizeof(*color_cache->colors_));
+ if (color_cache->colors_ == NULL) return 0;
+ color_cache->hash_shift_ = 32 - hash_bits;
+ color_cache->hash_bits_ = hash_bits;
return 1;
}
-void VP8LColorCacheClear(VP8LColorCache* const cc) {
- if (cc != NULL) {
- WebPSafeFree(cc->colors_);
- cc->colors_ = NULL;
+void VP8LColorCacheClear(VP8LColorCache* const color_cache) {
+ if (color_cache != NULL) {
+ WebPSafeFree(color_cache->colors_);
+ color_cache->colors_ = NULL;
}
}
diff --git a/thirdparty/libwebp/src/utils/huffman_encode_utils.c b/thirdparty/libwebp/src/utils/huffman_encode_utils.c
index 6f3b1bbe02..fd7a47d8f7 100644
--- a/thirdparty/libwebp/src/utils/huffman_encode_utils.c
+++ b/thirdparty/libwebp/src/utils/huffman_encode_utils.c
@@ -404,8 +404,7 @@ static void ConvertBitDepthsToSymbols(HuffmanTreeCode* const tree) {
// Main entry point
void VP8LCreateHuffmanTree(uint32_t* const histogram, int tree_depth_limit,
- uint8_t* const buf_rle,
- HuffmanTree* const huff_tree,
+ uint8_t* const buf_rle, HuffmanTree* const huff_tree,
HuffmanTreeCode* const huff_code) {
const int num_symbols = huff_code->num_symbols;
memset(buf_rle, 0, num_symbols * sizeof(*buf_rle));
diff --git a/thirdparty/libwebp/src/utils/huffman_encode_utils.h b/thirdparty/libwebp/src/utils/huffman_encode_utils.h
index 3e6763ce49..3f7f1d8074 100644
--- a/thirdparty/libwebp/src/utils/huffman_encode_utils.h
+++ b/thirdparty/libwebp/src/utils/huffman_encode_utils.h
@@ -51,7 +51,7 @@ int VP8LCreateCompressedHuffmanTree(const HuffmanTreeCode* const tree,
// huffman code tree.
void VP8LCreateHuffmanTree(uint32_t* const histogram, int tree_depth_limit,
uint8_t* const buf_rle, HuffmanTree* const huff_tree,
- HuffmanTreeCode* const tree);
+ HuffmanTreeCode* const huff_code);
#ifdef __cplusplus
}
diff --git a/thirdparty/libwebp/src/utils/rescaler_utils.c b/thirdparty/libwebp/src/utils/rescaler_utils.c
index 4bcae24af5..a0581a14b1 100644
--- a/thirdparty/libwebp/src/utils/rescaler_utils.c
+++ b/thirdparty/libwebp/src/utils/rescaler_utils.c
@@ -12,66 +12,74 @@
// Author: Skal (pascal.massimino@gmail.com)
#include <assert.h>
+#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include "src/dsp/dsp.h"
#include "src/utils/rescaler_utils.h"
+#include "src/utils/utils.h"
//------------------------------------------------------------------------------
-void WebPRescalerInit(WebPRescaler* const wrk, int src_width, int src_height,
- uint8_t* const dst,
- int dst_width, int dst_height, int dst_stride,
- int num_channels, rescaler_t* const work) {
+int WebPRescalerInit(WebPRescaler* const rescaler,
+ int src_width, int src_height,
+ uint8_t* const dst,
+ int dst_width, int dst_height, int dst_stride,
+ int num_channels, rescaler_t* const work) {
const int x_add = src_width, x_sub = dst_width;
const int y_add = src_height, y_sub = dst_height;
- wrk->x_expand = (src_width < dst_width);
- wrk->y_expand = (src_height < dst_height);
- wrk->src_width = src_width;
- wrk->src_height = src_height;
- wrk->dst_width = dst_width;
- wrk->dst_height = dst_height;
- wrk->src_y = 0;
- wrk->dst_y = 0;
- wrk->dst = dst;
- wrk->dst_stride = dst_stride;
- wrk->num_channels = num_channels;
+ const uint64_t total_size = 2ull * dst_width * num_channels * sizeof(*work);
+ if (!CheckSizeOverflow(total_size)) return 0;
+
+ rescaler->x_expand = (src_width < dst_width);
+ rescaler->y_expand = (src_height < dst_height);
+ rescaler->src_width = src_width;
+ rescaler->src_height = src_height;
+ rescaler->dst_width = dst_width;
+ rescaler->dst_height = dst_height;
+ rescaler->src_y = 0;
+ rescaler->dst_y = 0;
+ rescaler->dst = dst;
+ rescaler->dst_stride = dst_stride;
+ rescaler->num_channels = num_channels;
// for 'x_expand', we use bilinear interpolation
- wrk->x_add = wrk->x_expand ? (x_sub - 1) : x_add;
- wrk->x_sub = wrk->x_expand ? (x_add - 1) : x_sub;
- if (!wrk->x_expand) { // fx_scale is not used otherwise
- wrk->fx_scale = WEBP_RESCALER_FRAC(1, wrk->x_sub);
+ rescaler->x_add = rescaler->x_expand ? (x_sub - 1) : x_add;
+ rescaler->x_sub = rescaler->x_expand ? (x_add - 1) : x_sub;
+ if (!rescaler->x_expand) { // fx_scale is not used otherwise
+ rescaler->fx_scale = WEBP_RESCALER_FRAC(1, rescaler->x_sub);
}
// vertical scaling parameters
- wrk->y_add = wrk->y_expand ? y_add - 1 : y_add;
- wrk->y_sub = wrk->y_expand ? y_sub - 1 : y_sub;
- wrk->y_accum = wrk->y_expand ? wrk->y_sub : wrk->y_add;
- if (!wrk->y_expand) {
+ rescaler->y_add = rescaler->y_expand ? y_add - 1 : y_add;
+ rescaler->y_sub = rescaler->y_expand ? y_sub - 1 : y_sub;
+ rescaler->y_accum = rescaler->y_expand ? rescaler->y_sub : rescaler->y_add;
+ if (!rescaler->y_expand) {
// This is WEBP_RESCALER_FRAC(dst_height, x_add * y_add) without the cast.
- // Its value is <= WEBP_RESCALER_ONE, because dst_height <= wrk->y_add, and
- // wrk->x_add >= 1;
- const uint64_t ratio =
- (uint64_t)dst_height * WEBP_RESCALER_ONE / (wrk->x_add * wrk->y_add);
+ // Its value is <= WEBP_RESCALER_ONE, because dst_height <= rescaler->y_add
+ // and rescaler->x_add >= 1;
+ const uint64_t num = (uint64_t)dst_height * WEBP_RESCALER_ONE;
+ const uint64_t den = (uint64_t)rescaler->x_add * rescaler->y_add;
+ const uint64_t ratio = num / den;
if (ratio != (uint32_t)ratio) {
// When ratio == WEBP_RESCALER_ONE, we can't represent the ratio with the
// current fixed-point precision. This happens when src_height ==
- // wrk->y_add (which == src_height), and wrk->x_add == 1.
+ // rescaler->y_add (which == src_height), and rescaler->x_add == 1.
// => We special-case fxy_scale = 0, in WebPRescalerExportRow().
- wrk->fxy_scale = 0;
+ rescaler->fxy_scale = 0;
} else {
- wrk->fxy_scale = (uint32_t)ratio;
+ rescaler->fxy_scale = (uint32_t)ratio;
}
- wrk->fy_scale = WEBP_RESCALER_FRAC(1, wrk->y_sub);
+ rescaler->fy_scale = WEBP_RESCALER_FRAC(1, rescaler->y_sub);
} else {
- wrk->fy_scale = WEBP_RESCALER_FRAC(1, wrk->x_add);
- // wrk->fxy_scale is unused here.
+ rescaler->fy_scale = WEBP_RESCALER_FRAC(1, rescaler->x_add);
+ // rescaler->fxy_scale is unused here.
}
- wrk->irow = work;
- wrk->frow = work + num_channels * dst_width;
- memset(work, 0, 2 * dst_width * num_channels * sizeof(*work));
+ rescaler->irow = work;
+ rescaler->frow = work + num_channels * dst_width;
+ memset(work, 0, (size_t)total_size);
WebPRescalerDspInit();
+ return 1;
}
int WebPRescalerGetScaledDimensions(int src_width, int src_height,
@@ -82,6 +90,7 @@ int WebPRescalerGetScaledDimensions(int src_width, int src_height,
{
int width = *scaled_width;
int height = *scaled_height;
+ const int max_size = INT_MAX / 2;
// if width is unspecified, scale original proportionally to height ratio.
if (width == 0 && src_height > 0) {
@@ -94,7 +103,7 @@ int WebPRescalerGetScaledDimensions(int src_width, int src_height,
(int)(((uint64_t)src_height * width + src_width - 1) / src_width);
}
// Check if the overall dimensions still make sense.
- if (width <= 0 || height <= 0) {
+ if (width <= 0 || height <= 0 || width > max_size || height > max_size) {
return 0;
}
@@ -107,31 +116,34 @@ int WebPRescalerGetScaledDimensions(int src_width, int src_height,
//------------------------------------------------------------------------------
// all-in-one calls
-int WebPRescaleNeededLines(const WebPRescaler* const wrk, int max_num_lines) {
- const int num_lines = (wrk->y_accum + wrk->y_sub - 1) / wrk->y_sub;
+int WebPRescaleNeededLines(const WebPRescaler* const rescaler,
+ int max_num_lines) {
+ const int num_lines =
+ (rescaler->y_accum + rescaler->y_sub - 1) / rescaler->y_sub;
return (num_lines > max_num_lines) ? max_num_lines : num_lines;
}
-int WebPRescalerImport(WebPRescaler* const wrk, int num_lines,
+int WebPRescalerImport(WebPRescaler* const rescaler, int num_lines,
const uint8_t* src, int src_stride) {
int total_imported = 0;
- while (total_imported < num_lines && !WebPRescalerHasPendingOutput(wrk)) {
- if (wrk->y_expand) {
- rescaler_t* const tmp = wrk->irow;
- wrk->irow = wrk->frow;
- wrk->frow = tmp;
+ while (total_imported < num_lines &&
+ !WebPRescalerHasPendingOutput(rescaler)) {
+ if (rescaler->y_expand) {
+ rescaler_t* const tmp = rescaler->irow;
+ rescaler->irow = rescaler->frow;
+ rescaler->frow = tmp;
}
- WebPRescalerImportRow(wrk, src);
- if (!wrk->y_expand) { // Accumulate the contribution of the new row.
+ WebPRescalerImportRow(rescaler, src);
+ if (!rescaler->y_expand) { // Accumulate the contribution of the new row.
int x;
- for (x = 0; x < wrk->num_channels * wrk->dst_width; ++x) {
- wrk->irow[x] += wrk->frow[x];
+ for (x = 0; x < rescaler->num_channels * rescaler->dst_width; ++x) {
+ rescaler->irow[x] += rescaler->frow[x];
}
}
- ++wrk->src_y;
+ ++rescaler->src_y;
src += src_stride;
++total_imported;
- wrk->y_accum -= wrk->y_sub;
+ rescaler->y_accum -= rescaler->y_sub;
}
return total_imported;
}
diff --git a/thirdparty/libwebp/src/utils/rescaler_utils.h b/thirdparty/libwebp/src/utils/rescaler_utils.h
index ca41e42c4a..ef201ef86c 100644
--- a/thirdparty/libwebp/src/utils/rescaler_utils.h
+++ b/thirdparty/libwebp/src/utils/rescaler_utils.h
@@ -47,12 +47,13 @@ struct WebPRescaler {
};
// Initialize a rescaler given scratch area 'work' and dimensions of src & dst.
-void WebPRescalerInit(WebPRescaler* const rescaler,
- int src_width, int src_height,
- uint8_t* const dst,
- int dst_width, int dst_height, int dst_stride,
- int num_channels,
- rescaler_t* const work);
+// Returns false in case of error.
+int WebPRescalerInit(WebPRescaler* const rescaler,
+ int src_width, int src_height,
+ uint8_t* const dst,
+ int dst_width, int dst_height, int dst_stride,
+ int num_channels,
+ rescaler_t* const work);
// If either 'scaled_width' or 'scaled_height' (but not both) is 0 the value
// will be calculated preserving the aspect ratio, otherwise the values are
diff --git a/thirdparty/libwebp/src/utils/utils.c b/thirdparty/libwebp/src/utils/utils.c
index 764f752b82..9e464c16ce 100644
--- a/thirdparty/libwebp/src/utils/utils.c
+++ b/thirdparty/libwebp/src/utils/utils.c
@@ -101,6 +101,9 @@ static void Increment(int* const v) {
#if defined(MALLOC_LIMIT)
{
const char* const malloc_limit_str = getenv("MALLOC_LIMIT");
+#if MALLOC_LIMIT > 1
+ mem_limit = (size_t)MALLOC_LIMIT;
+#endif
if (malloc_limit_str != NULL) {
mem_limit = atoi(malloc_limit_str);
}
@@ -169,16 +172,16 @@ static int CheckSizeArgumentsOverflow(uint64_t nmemb, size_t size) {
const uint64_t total_size = nmemb * size;
if (nmemb == 0) return 1;
if ((uint64_t)size > WEBP_MAX_ALLOCABLE_MEMORY / nmemb) return 0;
- if (total_size != (size_t)total_size) return 0;
+ if (!CheckSizeOverflow(total_size)) return 0;
#if defined(PRINT_MEM_INFO) && defined(MALLOC_FAIL_AT)
if (countdown_to_fail > 0 && --countdown_to_fail == 0) {
return 0; // fake fail!
}
#endif
-#if defined(MALLOC_LIMIT)
+#if defined(PRINT_MEM_INFO) && defined(MALLOC_LIMIT)
if (mem_limit > 0) {
const uint64_t new_total_mem = (uint64_t)total_mem + total_size;
- if (new_total_mem != (size_t)new_total_mem ||
+ if (!CheckSizeOverflow(new_total_mem) ||
new_total_mem > mem_limit) {
return 0; // fake fail!
}
@@ -231,7 +234,7 @@ void WebPFree(void* ptr) {
void WebPCopyPlane(const uint8_t* src, int src_stride,
uint8_t* dst, int dst_stride, int width, int height) {
assert(src != NULL && dst != NULL);
- assert(src_stride >= width && dst_stride >= width);
+ assert(abs(src_stride) >= width && abs(dst_stride) >= width);
while (height-- > 0) {
memcpy(dst, src, width);
src += src_stride;
diff --git a/thirdparty/libwebp/src/utils/utils.h b/thirdparty/libwebp/src/utils/utils.h
index 2a3ec92678..ef04f108fe 100644
--- a/thirdparty/libwebp/src/utils/utils.h
+++ b/thirdparty/libwebp/src/utils/utils.h
@@ -42,6 +42,10 @@ extern "C" {
#endif
#endif // WEBP_MAX_ALLOCABLE_MEMORY
+static WEBP_INLINE int CheckSizeOverflow(uint64_t size) {
+ return size == (size_t)size;
+}
+
// size-checking safe malloc/calloc: verify that the requested size is not too
// large, or return NULL. You don't need to call these for constructs like
// malloc(sizeof(foo)), but only if there's picture-dependent size involved
@@ -107,24 +111,33 @@ static WEBP_INLINE void PutLE32(uint8_t* const data, uint32_t val) {
PutLE16(data + 2, (int)(val >> 16));
}
-// Returns (int)floor(log2(n)). n must be > 0.
// use GNU builtins where available.
#if defined(__GNUC__) && \
((__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || __GNUC__ >= 4)
+// Returns (int)floor(log2(n)). n must be > 0.
static WEBP_INLINE int BitsLog2Floor(uint32_t n) {
return 31 ^ __builtin_clz(n);
}
+// counts the number of trailing zero
+static WEBP_INLINE int BitsCtz(uint32_t n) { return __builtin_ctz(n); }
#elif defined(_MSC_VER) && _MSC_VER > 1310 && \
(defined(_M_X64) || defined(_M_IX86))
#include <intrin.h>
#pragma intrinsic(_BitScanReverse)
+#pragma intrinsic(_BitScanForward)
static WEBP_INLINE int BitsLog2Floor(uint32_t n) {
- unsigned long first_set_bit;
+ unsigned long first_set_bit; // NOLINT (runtime/int)
_BitScanReverse(&first_set_bit, n);
return first_set_bit;
}
-#else // default: use the C-version.
+static WEBP_INLINE int BitsCtz(uint32_t n) {
+ unsigned long first_set_bit; // NOLINT (runtime/int)
+ _BitScanForward(&first_set_bit, n);
+ return first_set_bit;
+}
+#else // default: use the (slow) C-version.
+#define WEBP_HAVE_SLOW_CLZ_CTZ // signal that the Clz/Ctz function are slow
// Returns 31 ^ clz(n) = log2(n). This is the default C-implementation, either
// based on table or not. Can be used as fallback if clz() is not available.
#define WEBP_NEED_LOG_TABLE_8BIT
@@ -139,6 +152,15 @@ static WEBP_INLINE int WebPLog2FloorC(uint32_t n) {
}
static WEBP_INLINE int BitsLog2Floor(uint32_t n) { return WebPLog2FloorC(n); }
+
+static WEBP_INLINE int BitsCtz(uint32_t n) {
+ int i;
+ for (i = 0; i < 32; ++i, n >>= 1) {
+ if (n & 1) return i;
+ }
+ return 32;
+}
+
#endif
//------------------------------------------------------------------------------
diff --git a/thirdparty/libwebp/src/webp/decode.h b/thirdparty/libwebp/src/webp/decode.h
index 80dd0ef0cc..44fcd64a84 100644
--- a/thirdparty/libwebp/src/webp/decode.h
+++ b/thirdparty/libwebp/src/webp/decode.h
@@ -453,7 +453,7 @@ struct WebPDecoderOptions {
int scaled_width, scaled_height; // final resolution
int use_threads; // if true, use multi-threaded decoding
int dithering_strength; // dithering strength (0=Off, 100=full)
- int flip; // flip output vertically
+ int flip; // if true, flip output vertically
int alpha_dithering_strength; // alpha dithering strength in [0..100]
uint32_t pad[5]; // padding for later use
diff --git a/thirdparty/libwebp/src/webp/encode.h b/thirdparty/libwebp/src/webp/encode.h
index 655166e7d4..b4c599df87 100644
--- a/thirdparty/libwebp/src/webp/encode.h
+++ b/thirdparty/libwebp/src/webp/encode.h
@@ -148,7 +148,8 @@ struct WebPConfig {
int use_delta_palette; // reserved for future lossless feature
int use_sharp_yuv; // if needed, use sharp (and slow) RGB->YUV conversion
- uint32_t pad[2]; // padding for later use
+ int qmin; // minimum permissible quality factor
+ int qmax; // maximum permissible quality factor
};
// Enumerate some predefined settings for WebPConfig, depending on the type
@@ -291,6 +292,11 @@ typedef enum WebPEncodingError {
#define WEBP_MAX_DIMENSION 16383
// Main exchange structure (input samples, output bytes, statistics)
+//
+// Once WebPPictureInit() has been called, it's ok to make all the INPUT fields
+// (use_argb, y/u/v, argb, ...) point to user-owned data, even if
+// WebPPictureAlloc() has been called. Depending on the value use_argb,
+// it's guaranteed that either *argb or *y/*u/*v content will be kept untouched.
struct WebPPicture {
// INPUT
//////////////
diff --git a/thirdparty/pcre2/AUTHORS b/thirdparty/pcre2/AUTHORS
index f001cb770e..bec8a1e5ad 100644
--- a/thirdparty/pcre2/AUTHORS
+++ b/thirdparty/pcre2/AUTHORS
@@ -5,10 +5,10 @@ Written by: Philip Hazel
Email local part: Philip.Hazel
Email domain: gmail.com
-University of Cambridge Computing Service,
+Retired from University of Cambridge Computing Service,
Cambridge, England.
-Copyright (c) 1997-2020 University of Cambridge
+Copyright (c) 1997-2021 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-2020 Zoltan Herczeg
+Copyright(c) 2010-2021 Zoltan Herczeg
All rights reserved.
@@ -30,7 +30,7 @@ Written by: Zoltan Herczeg
Email local part: hzmester
Emain domain: freemail.hu
-Copyright(c) 2009-2020 Zoltan Herczeg
+Copyright(c) 2009-2021 Zoltan Herczeg
All rights reserved.
####
diff --git a/thirdparty/pcre2/LICENCE b/thirdparty/pcre2/LICENCE
index 155d073127..b1ec61be44 100644
--- a/thirdparty/pcre2/LICENCE
+++ b/thirdparty/pcre2/LICENCE
@@ -23,10 +23,10 @@ Written by: Philip Hazel
Email local part: Philip.Hazel
Email domain: gmail.com
-University of Cambridge Computing Service,
+Retired from University of Cambridge Computing Service,
Cambridge, England.
-Copyright (c) 1997-2020 University of Cambridge
+Copyright (c) 1997-2021 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-2020 Zoltan Herczeg
+Copyright(c) 2010-2021 Zoltan Herczeg
All rights reserved.
@@ -48,7 +48,7 @@ Written by: Zoltan Herczeg
Email local part: hzmester
Email domain: freemail.hu
-Copyright(c) 2009-2020 Zoltan Herczeg
+Copyright(c) 2009-2021 Zoltan Herczeg
All rights reserved.
diff --git a/thirdparty/pcre2/src/config.h b/thirdparty/pcre2/src/config.h
index 10f4104790..a13593715e 100644
--- a/thirdparty/pcre2/src/config.h
+++ b/thirdparty/pcre2/src/config.h
@@ -85,8 +85,8 @@ sure both macros are undefined; an emulation function will then be used. */
/* Define to 1 if you have the `memmove' function. */
/* #undef HAVE_MEMMOVE */
-/* Define to 1 if you have the <memory.h> header file. */
-/* #undef HAVE_MEMORY_H */
+/* Define to 1 if you have the <minix/config.h> header file. */
+/* #undef HAVE_MINIX_CONFIG_H */
/* Define to 1 if you have the `mkostemp' function. */
/* #undef HAVE_MKOSTEMP */
@@ -103,12 +103,18 @@ sure both macros are undefined; an emulation function will then be used. */
/* Define to 1 if you have the <readline/readline.h> header file. */
/* #undef HAVE_READLINE_READLINE_H */
+/* Define to 1 if you have the `realpath' function. */
+/* #undef HAVE_REALPATH */
+
/* Define to 1 if you have the `secure_getenv' function. */
/* #undef HAVE_SECURE_GETENV */
/* Define to 1 if you have the <stdint.h> header file. */
/* #undef HAVE_STDINT_H */
+/* Define to 1 if you have the <stdio.h> header file. */
+/* #undef HAVE_STDIO_H */
+
/* Define to 1 if you have the <stdlib.h> header file. */
/* #undef HAVE_STDLIB_H */
@@ -136,6 +142,9 @@ sure both macros are undefined; an emulation function will then be used. */
/* Define to 1 if the compiler supports simple visibility declarations. */
/* #undef HAVE_VISIBILITY */
+/* Define to 1 if you have the <wchar.h> header file. */
+/* #undef HAVE_WCHAR_H */
+
/* Define to 1 if you have the <windows.h> header file. */
/* #undef HAVE_WINDOWS_H */
@@ -224,7 +233,7 @@ sure both macros are undefined; an emulation function will then be used. */
#define PACKAGE_NAME "PCRE2"
/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "PCRE2 10.36"
+#define PACKAGE_STRING "PCRE2 10.39"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "pcre2"
@@ -233,7 +242,7 @@ sure both macros are undefined; an emulation function will then be used. */
#define PACKAGE_URL ""
/* Define to the version of this package. */
-#define PACKAGE_VERSION "10.36"
+#define PACKAGE_VERSION "10.39"
/* The value of PARENS_NEST_LIMIT specifies the maximum depth of nested
parentheses (of any kind) in a pattern. This limits the amount of system
@@ -286,7 +295,9 @@ sure both macros are undefined; an emulation function will then be used. */
unless SUPPORT_JIT is also defined. */
/* #undef SLJIT_PROT_EXECUTABLE_ALLOCATOR */
-/* Define to 1 if you have the ANSI C header files. */
+/* Define to 1 if all of the C90 standard headers exist (not just the ones
+ required in a freestanding environment). This macro is provided for
+ backward compatibility; new code need not use it. */
/* #undef STDC_HEADERS */
/* Define to any value to enable support for Just-In-Time compiling. */
@@ -340,35 +351,91 @@ sure both macros are undefined; an emulation function will then be used. */
#ifndef _ALL_SOURCE
# define _ALL_SOURCE 1
#endif
+/* Enable general extensions on macOS. */
+#ifndef _DARWIN_C_SOURCE
+# define _DARWIN_C_SOURCE 1
+#endif
+/* Enable general extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# define __EXTENSIONS__ 1
+#endif
/* Enable GNU extensions on systems that have them. */
#ifndef _GNU_SOURCE
# define _GNU_SOURCE 1
#endif
-/* Enable threading extensions on Solaris. */
+/* Enable X/Open compliant socket functions that do not require linking
+ with -lxnet on HP-UX 11.11. */
+#ifndef _HPUX_ALT_XOPEN_SOCKET_API
+# define _HPUX_ALT_XOPEN_SOCKET_API 1
+#endif
+/* Identify the host operating system as Minix.
+ This macro does not affect the system headers' behavior.
+ A future release of Autoconf may stop defining this macro. */
+#ifndef _MINIX
+/* # undef _MINIX */
+#endif
+/* Enable general extensions on NetBSD.
+ Enable NetBSD compatibility extensions on Minix. */
+#ifndef _NETBSD_SOURCE
+# define _NETBSD_SOURCE 1
+#endif
+/* Enable OpenBSD compatibility extensions on NetBSD.
+ Oddly enough, this does nothing on OpenBSD. */
+#ifndef _OPENBSD_SOURCE
+# define _OPENBSD_SOURCE 1
+#endif
+/* Define to 1 if needed for POSIX-compatible behavior. */
+#ifndef _POSIX_SOURCE
+/* # undef _POSIX_SOURCE */
+#endif
+/* Define to 2 if needed for POSIX-compatible behavior. */
+#ifndef _POSIX_1_SOURCE
+/* # undef _POSIX_1_SOURCE */
+#endif
+/* Enable POSIX-compatible threading on Solaris. */
#ifndef _POSIX_PTHREAD_SEMANTICS
# define _POSIX_PTHREAD_SEMANTICS 1
#endif
+/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */
+#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__
+# define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */
+#ifndef __STDC_WANT_IEC_60559_BFP_EXT__
+# define __STDC_WANT_IEC_60559_BFP_EXT__ 1
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */
+#ifndef __STDC_WANT_IEC_60559_DFP_EXT__
+# define __STDC_WANT_IEC_60559_DFP_EXT__ 1
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */
+#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__
+# define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-3:2015. */
+#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__
+# define __STDC_WANT_IEC_60559_TYPES_EXT__ 1
+#endif
+/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */
+#ifndef __STDC_WANT_LIB_EXT2__
+# define __STDC_WANT_LIB_EXT2__ 1
+#endif
+/* Enable extensions specified by ISO/IEC 24747:2009. */
+#ifndef __STDC_WANT_MATH_SPEC_FUNCS__
+# define __STDC_WANT_MATH_SPEC_FUNCS__ 1
+#endif
/* Enable extensions on HP NonStop. */
#ifndef _TANDEM_SOURCE
# define _TANDEM_SOURCE 1
#endif
-/* Enable general extensions on Solaris. */
-#ifndef __EXTENSIONS__
-# define __EXTENSIONS__ 1
+/* Enable X/Open extensions. Define to 500 only if necessary
+ to make mbstate_t available. */
+#ifndef _XOPEN_SOURCE
+/* # undef _XOPEN_SOURCE */
#endif
/* Version number of package */
-#define VERSION "10.36"
-
-/* Define to 1 if on MINIX. */
-/* #undef _MINIX */
-
-/* Define to 2 if the system does not provide POSIX.1 features except with
- this defined. */
-/* #undef _POSIX_1_SOURCE */
-
-/* Define to 1 if you need to in order for `stat' and other things to work. */
-/* #undef _POSIX_SOURCE */
+#define VERSION "10.39"
/* Define to empty if `const' does not conform to ANSI C. */
/* #undef const */
diff --git a/thirdparty/pcre2/src/pcre2.h b/thirdparty/pcre2/src/pcre2.h
index f204ec8180..90a97d9cb7 100644
--- a/thirdparty/pcre2/src/pcre2.h
+++ b/thirdparty/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-2020 University of Cambridge
+ Copyright (c) 2016-2021 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 36
+#define PCRE2_MINOR 39
#define PCRE2_PRERELEASE
-#define PCRE2_DATE 2020-12-04
+#define PCRE2_DATE 2021-10-29
/* When an application links to a PCRE DLL in Windows, the symbols that are
imported have to be identified as such. When building PCRE2, the appropriate
@@ -84,8 +84,8 @@ set, we ensure here that it has no effect. */
/* Have to include limits.h, stdlib.h, and inttypes.h to ensure that size_t and
uint8_t, UCHAR_MAX, etc are defined. Some systems that do have inttypes.h do
not have stdint.h, which is why we use inttypes.h, which according to the C
-standard is a superset of stdint.h. If none of these headers are available,
-the relevant values must be provided by some other means. */
+standard is a superset of stdint.h. If inttypes.h is not available the build
+will break and the relevant values must be provided by some other means. */
#include <limits.h>
#include <stdlib.h>
@@ -152,6 +152,7 @@ D is inspected during pcre2_dfa_match() execution
#define PCRE2_EXTRA_MATCH_LINE 0x00000008u /* C */
#define PCRE2_EXTRA_ESCAPED_CR_IS_LF 0x00000010u /* C */
#define PCRE2_EXTRA_ALT_BSUX 0x00000020u /* C */
+#define PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK 0x00000040u /* C */
/* These are for pcre2_jit_compile(). */
@@ -311,6 +312,7 @@ pcre2_pattern_convert(). */
#define PCRE2_ERROR_SCRIPT_RUN_NOT_AVAILABLE 196
#define PCRE2_ERROR_TOO_MANY_CAPTURES 197
#define PCRE2_ERROR_CONDITION_ATOMIC_ASSERTION_EXPECTED 198
+#define PCRE2_ERROR_BACKSLASH_K_IN_LOOKAROUND 199
/* "Expected" matching error codes: no match and partial match. */
diff --git a/thirdparty/pcre2/src/pcre2_auto_possess.c b/thirdparty/pcre2/src/pcre2_auto_possess.c
index c64cf856d1..e5e0895682 100644
--- a/thirdparty/pcre2/src/pcre2_auto_possess.c
+++ b/thirdparty/pcre2/src/pcre2_auto_possess.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-2020 University of Cambridge
+ New API code Copyright (c) 2016-2021 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -490,6 +490,7 @@ switch(c)
list[2] = (uint32_t)(end - code);
return end;
}
+
return NULL; /* Opcode not accepted */
}
@@ -1186,12 +1187,16 @@ for (;;)
c = *repeat_opcode;
if (c >= OP_CRSTAR && c <= OP_CRMINRANGE)
{
- /* end must not be NULL. */
- end = get_chr_property_list(code, utf, ucp, cb->fcc, list);
+ /* The return from get_chr_property_list() will never be NULL when
+ *code (aka c) is one of the three class opcodes. However, gcc with
+ -fanalyzer notes that a NULL return is possible, and grumbles. Hence we
+ put in a check. */
+ end = get_chr_property_list(code, utf, ucp, cb->fcc, list);
list[1] = (c & 1) == 0;
- if (compare_opcodes(end, utf, ucp, cb, list, end, &rec_limit))
+ if (end != NULL &&
+ compare_opcodes(end, utf, ucp, cb, list, end, &rec_limit))
{
switch (c)
{
diff --git a/thirdparty/pcre2/src/pcre2_compile.c b/thirdparty/pcre2/src/pcre2_compile.c
index e811f12f02..383159be76 100644
--- a/thirdparty/pcre2/src/pcre2_compile.c
+++ b/thirdparty/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-2020 University of Cambridge
+ New API code Copyright (c) 2016-2021 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -137,7 +137,7 @@ static BOOL
static int
check_lookbehinds(uint32_t *, uint32_t **, parsed_recurse_check *,
- compile_block *);
+ compile_block *, int *);
/*************************************************
@@ -782,12 +782,15 @@ are allowed. */
#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_ESCAPED_CR_IS_LF|PCRE2_EXTRA_ALT_BSUX| \
+ PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK)
/* Compile time error code numbers. They are given names so that they can more
easily be tracked. When a new number is added, the tables called eint1 and
eint2 in pcre2posix.c may need to be updated, and a new error text must be
-added to compile_error_texts in pcre2_error.c. */
+added to compile_error_texts in pcre2_error.c. Also, the error codes in
+pcre2.h.in must be updated - their values are exactly 100 greater than these
+values. */
enum { ERR0 = COMPILE_ERROR_BASE,
ERR1, ERR2, ERR3, ERR4, ERR5, ERR6, ERR7, ERR8, ERR9, ERR10,
@@ -799,7 +802,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 };
+ ERR91, ERR92, ERR93, ERR94, ERR95, ERR96, ERR97, ERR98, ERR99 };
/* 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
@@ -1398,32 +1401,47 @@ static BOOL
read_repeat_counts(PCRE2_SPTR *ptrptr, PCRE2_SPTR ptrend, uint32_t *minp,
uint32_t *maxp, int *errorcodeptr)
{
-PCRE2_SPTR p = *ptrptr;
+PCRE2_SPTR p;
BOOL yield = FALSE;
+BOOL had_comma = FALSE;
int32_t min = 0;
int32_t max = REPEAT_UNLIMITED; /* This value is larger than MAX_REPEAT_COUNT */
-/* NB read_number() initializes the error code to zero. The only error is for a
-number that is too big. */
+/* Check the syntax */
+
+*errorcodeptr = 0;
+for (p = *ptrptr;; p++)
+ {
+ 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)
+ {
+ if (had_comma) return FALSE;
+ had_comma = TRUE;
+ }
+ else return FALSE;
+ }
+
+/* The only error from read_number() is for a number that is too big. */
+p = *ptrptr;
if (!read_number(&p, ptrend, -1, MAX_REPEAT_COUNT, ERR5, &min, errorcodeptr))
goto EXIT;
-if (p >= ptrend) goto EXIT;
-
if (*p == CHAR_RIGHT_CURLY_BRACKET)
{
p++;
max = min;
}
-
else
{
- if (*p++ != CHAR_COMMA || p >= ptrend) goto EXIT;
- if (*p != CHAR_RIGHT_CURLY_BRACKET)
+ if (*(++p) != CHAR_RIGHT_CURLY_BRACKET)
{
if (!read_number(&p, ptrend, -1, MAX_REPEAT_COUNT, ERR5, &max,
- errorcodeptr) || p >= ptrend || *p != CHAR_RIGHT_CURLY_BRACKET)
+ errorcodeptr))
goto EXIT;
if (max < min)
{
@@ -1438,11 +1456,10 @@ yield = TRUE;
if (minp != NULL) *minp = (uint32_t)min;
if (maxp != NULL) *maxp = (uint32_t)max;
-/* Update the pattern pointer on success, or after an error, but not when
-the result is "not a repeat quantifier". */
+/* Update the pattern pointer */
EXIT:
-if (yield || *errorcodeptr != 0) *ptrptr = p;
+*ptrptr = p;
return yield;
}
@@ -1776,19 +1793,23 @@ else
{
oldptr = ptr;
ptr--; /* Back to the digit */
- if (!read_number(&ptr, ptrend, -1, INT_MAX/10 - 1, ERR61, &s,
- errorcodeptr))
- break;
- /* \1 to \9 are always back references. \8x and \9x are too; \1x to \7x
+ /* As we know we are at a digit, the only possible error from
+ read_number() is a number that is too large to be a group number. In this
+ case we fall through handle this as not a group reference. If we have
+ read a small enough number, check for a back reference.
+
+ \1 to \9 are always back references. \8x and \9x are too; \1x to \7x
are octal escapes if there are not that many previous captures. */
- if (s < 10 || oldptr[-1] >= CHAR_8 || s <= (int)cb->bracount)
+ if (read_number(&ptr, ptrend, -1, INT_MAX/10 - 1, 0, &s, errorcodeptr) &&
+ (s < 10 || oldptr[-1] >= CHAR_8 || s <= (int)cb->bracount))
{
if (s > (int)MAX_GROUP_NUMBER) *errorcodeptr = ERR61;
else escape = -s; /* Indicates a back reference */
break;
}
+
ptr = oldptr; /* Put the pointer back and fall through */
}
@@ -7781,6 +7802,16 @@ for (;; pptr++)
}
#endif
+ /* \K is forbidden in lookarounds since 10.38 because that's what Perl has
+ 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)
+ {
+ *errorcodeptr = ERR99;
+ return 0;
+ }
+
/* 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
@@ -9130,7 +9161,7 @@ for (;; pptr++)
case META_LOOKAHEAD:
case META_LOOKAHEADNOT:
case META_LOOKAHEAD_NA:
- *errcodeptr = check_lookbehinds(pptr + 1, &pptr, recurses, cb);
+ *errcodeptr = check_lookbehinds(pptr + 1, &pptr, recurses, cb, lcptr);
if (*errcodeptr != 0) return -1;
/* Ignore any qualifiers that follow a lookahead assertion. */
@@ -9470,16 +9501,16 @@ Arguments
retptr if not NULL, return the ket pointer here
recurses chain of recurse_check to catch mutual recursion
cb points to the compile block
+ lcptr points to loop counter
Returns: 0 on success, or an errorcode (cb->erroroffset will be set)
*/
static int
check_lookbehinds(uint32_t *pptr, uint32_t **retptr,
- parsed_recurse_check *recurses, compile_block *cb)
+ parsed_recurse_check *recurses, compile_block *cb, int *lcptr)
{
int errorcode = 0;
-int loopcount = 0;
int nestlevel = 0;
cb->erroroffset = PCRE2_UNSET;
@@ -9605,7 +9636,7 @@ for (; *pptr != META_END; pptr++)
case META_LOOKBEHIND:
case META_LOOKBEHINDNOT:
case META_LOOKBEHIND_NA:
- if (!set_lookbehind_lengths(&pptr, &errorcode, &loopcount, recurses, cb))
+ if (!set_lookbehind_lengths(&pptr, &errorcode, lcptr, recurses, cb))
return errorcode;
break;
}
@@ -10060,7 +10091,8 @@ lengths. */
if (has_lookbehind)
{
- errorcode = check_lookbehinds(cb.parsed_pattern, NULL, NULL, &cb);
+ int loopcount = 0;
+ errorcode = check_lookbehinds(cb.parsed_pattern, NULL, NULL, &cb, &loopcount);
if (errorcode != 0) goto HAD_CB_ERROR;
}
diff --git a/thirdparty/pcre2/src/pcre2_dfa_match.c b/thirdparty/pcre2/src/pcre2_dfa_match.c
index 625695b7cb..060dc7669a 100644
--- a/thirdparty/pcre2/src/pcre2_dfa_match.c
+++ b/thirdparty/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-2020 University of Cambridge
+ New API code Copyright (c) 2016-2021 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -3256,8 +3256,8 @@ BOOL has_first_cu = FALSE;
BOOL has_req_cu = FALSE;
#if PCRE2_CODE_UNIT_WIDTH == 8
-BOOL memchr_not_found_first_cu = FALSE;
-BOOL memchr_not_found_first_cu2 = FALSE;
+PCRE2_SPTR memchr_found_first_cu = NULL;
+PCRE2_SPTR memchr_found_first_cu2 = NULL;
#endif
PCRE2_UCHAR first_cu = 0;
@@ -3648,13 +3648,7 @@ for (;;)
}
}
- /* Not anchored. Advance to a unique first code unit if there is one. In
- 8-bit mode, the use of memchr() gives a big speed up, even though we have
- to call it twice in caseless mode, in order to find the earliest occurrence
- of the character in either of its cases. If a call to memchr() that
- searches the rest of the subject fails to find one case, remember that in
- order not to keep on repeating the search. This can make a huge difference
- when the strings are very long and only one case is present. */
+ /* Not anchored. Advance to a unique first code unit if there is one. */
else
{
@@ -3662,43 +3656,68 @@ for (;;)
{
if (first_cu != first_cu2) /* Caseless */
{
+ /* In 16-bit and 32_bit modes we have to do our own search, so can
+ look for both cases at once. */
+
#if PCRE2_CODE_UNIT_WIDTH != 8
PCRE2_UCHAR smc;
while (start_match < end_subject &&
(smc = UCHAR21TEST(start_match)) != first_cu &&
- smc != first_cu2)
+ smc != first_cu2)
start_match++;
+#else
+ /* In 8-bit mode, the use of memchr() gives a big speed up, even
+ though we have to call it twice in order to find the earliest
+ occurrence of the code unit in either of its cases. Caching is used
+ to remember the positions of previously found code units. This can
+ make a huge difference when the strings are very long and only one
+ case is actually present. */
-#else /* 8-bit code units */
PCRE2_SPTR pp1 = NULL;
PCRE2_SPTR pp2 = NULL;
- PCRE2_SIZE cu2size = end_subject - start_match;
+ PCRE2_SIZE searchlength = end_subject - start_match;
- if (!memchr_not_found_first_cu)
+ /* If we haven't got a previously found position for first_cu, or if
+ the current starting position is later, we need to do a search. If
+ the code unit is not found, set it to the end. */
+
+ if (memchr_found_first_cu == NULL ||
+ start_match > memchr_found_first_cu)
{
- pp1 = memchr(start_match, first_cu, end_subject - start_match);
- if (pp1 == NULL) memchr_not_found_first_cu = TRUE;
- else cu2size = pp1 - start_match;
+ pp1 = memchr(start_match, first_cu, searchlength);
+ memchr_found_first_cu = (pp1 == NULL)? end_subject : pp1;
}
- /* If pp1 is not NULL, we have arranged to search only as far as pp1,
- to see if the other case is earlier, so we can set "not found" only
- when both searches have returned NULL. */
+ /* If the start is before a previously found position, use the
+ previous position, or NULL if a previous search failed. */
+
+ else pp1 = (memchr_found_first_cu == end_subject)? NULL :
+ memchr_found_first_cu;
- if (!memchr_not_found_first_cu2)
+ /* Do the same thing for the other case. */
+
+ if (memchr_found_first_cu2 == NULL ||
+ start_match > memchr_found_first_cu2)
{
- pp2 = memchr(start_match, first_cu2, cu2size);
- memchr_not_found_first_cu2 = (pp2 == NULL && pp1 == NULL);
+ pp2 = memchr(start_match, first_cu2, searchlength);
+ memchr_found_first_cu2 = (pp2 == NULL)? end_subject : pp2;
}
+ else pp2 = (memchr_found_first_cu2 == end_subject)? NULL :
+ memchr_found_first_cu2;
+
+ /* Set the start to the end of the subject if neither case was found.
+ Otherwise, use the earlier found point. */
+
if (pp1 == NULL)
start_match = (pp2 == NULL)? end_subject : pp2;
else
start_match = (pp2 == NULL || pp1 < pp2)? pp1 : pp2;
-#endif
+
+#endif /* 8-bit handling */
}
- /* The caseful case */
+ /* The caseful case is much simpler. */
else
{
diff --git a/thirdparty/pcre2/src/pcre2_error.c b/thirdparty/pcre2/src/pcre2_error.c
index c61648cb7f..3dee63d0db 100644
--- a/thirdparty/pcre2/src/pcre2_error.c
+++ b/thirdparty/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-2019 University of Cambridge
+ New API code Copyright (c) 2016-2021 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -186,6 +186,7 @@ static const unsigned char compile_error_texts[] =
"script runs require Unicode support, which this version of PCRE2 does not have\0"
"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"
;
/* Match-time and UTF error texts are in the same format. */
diff --git a/thirdparty/pcre2/src/pcre2_jit_compile.c b/thirdparty/pcre2/src/pcre2_jit_compile.c
index 1977d28aa5..db2ce65598 100644
--- a/thirdparty/pcre2/src/pcre2_jit_compile.c
+++ b/thirdparty/pcre2/src/pcre2_jit_compile.c
@@ -1226,7 +1226,7 @@ while (cc < ccend)
return TRUE;
}
-#define EARLY_FAIL_ENHANCE_MAX (1 + 1)
+#define EARLY_FAIL_ENHANCE_MAX (1 + 3)
/*
start:
@@ -1236,23 +1236,28 @@ start:
return: current number of iterators enhanced with fast fail
*/
-static int detect_early_fail(compiler_common *common, PCRE2_SPTR cc, int *private_data_start, sljit_s32 depth, int 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)
{
+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;
-BOOL fast_forward_allowed = TRUE;
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;
+
do
{
count = start;
- next_alt = cc + GET(cc, 1);
cc += 1 + LINK_SIZE + ((*cc == OP_CBRA) ? IMM2_SIZE : 0);
while (TRUE)
@@ -1475,31 +1480,20 @@ do
case OP_CBRA:
end = cc + GET(cc, 1);
- if (*end == OP_KET && PRIVATE_DATA(end) == 0)
- {
- if (*cc == OP_CBRA)
- {
- if (common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] == 0)
- break;
- cc += IMM2_SIZE;
- }
-
- cc += 1 + LINK_SIZE;
- continue;
- }
-
+ 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 || PRIVATE_DATA(end) != 0)
+ if (*end != OP_KET || (*cc == OP_CBRA && common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] == 0))
break;
- if (*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);
+
+ if (PRIVATE_DATA(cc) != 0)
+ common->private_data_ptrs[begin - common->start] = 1;
- count = detect_early_fail(common, cc, private_data_start, depth + 1, count);
if (count < EARLY_FAIL_ENHANCE_MAX)
{
cc = end + (1 + LINK_SIZE);
@@ -1521,7 +1515,7 @@ do
{
count++;
- if (fast_forward_allowed && *next_alt == OP_KET)
+ 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;
@@ -1555,6 +1549,8 @@ do
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)
@@ -1569,8 +1565,8 @@ do
else if (result < count)
result = count;
- fast_forward_allowed = FALSE;
cc = next_alt;
+ next_alt = cc + GET(cc, 1);
}
while (*cc == OP_ALT);
@@ -1620,11 +1616,12 @@ sljit_sw length = end - begin;
sljit_s32 min, max, i;
/* Detect fixed iterations first. */
-if (end[-(1 + LINK_SIZE)] != OP_KET)
+if (end[-(1 + LINK_SIZE)] != OP_KET || PRIVATE_DATA(begin) != 0)
return FALSE;
-/* Already detected repeat. */
-if (common->private_data_ptrs[end - common->start - LINK_SIZE] != 0)
+/* /(?:AB){4,6}/ is currently converted to /(?:AB){3}(?AB){1,3}/
+ * Skip the check of the second part. */
+if (PRIVATE_DATA(end - LINK_SIZE) == 0)
return TRUE;
next = end;
@@ -1763,6 +1760,7 @@ while (cc < ccend)
if (private_data_ptr > SLJIT_MAX_LOCAL_SIZE)
break;
+ /* When the bracket is prefixed by a zero iteration, skip the repeat check (at this point). */
if (repeat_check && (*cc == OP_ONCE || *cc == OP_BRA || *cc == OP_CBRA || *cc == OP_COND))
{
if (detect_repeat(common, cc))
@@ -1813,6 +1811,7 @@ while (cc < ccend)
case OP_COND:
/* Might be a hidden SCOND. */
+ common->private_data_ptrs[cc - common->start] = 0;
alternative = cc + GET(cc, 1);
if (*alternative == OP_KETRMAX || *alternative == OP_KETRMIN)
{
@@ -4203,9 +4202,6 @@ TMP2 is not used. Otherwise TMP2 must contain the start of the subject buffer,
and it is destroyed. Does not modify STR_PTR for invalid character sequences. */
DEFINE_COMPILER;
-SLJIT_UNUSED_ARG(backtracks);
-SLJIT_UNUSED_ARG(must_be_valid);
-
#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
struct sljit_jump *jump;
#endif
@@ -4279,6 +4275,10 @@ if (common->invalid_utf && !must_be_valid)
}
#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16|32] */
#endif /* SUPPORT_UNICODE */
+
+SLJIT_UNUSED_ARG(backtracks);
+SLJIT_UNUSED_ARG(must_be_valid);
+
OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
}
@@ -8141,7 +8141,7 @@ switch(type)
}
else
OP2(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_UNUSED, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTEOL);
- add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO32));
+ add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO));
if (!common->endonly)
compile_simple_assertion_matchingpath(common, OP_EODN, cc, backtracks);
@@ -8161,7 +8161,7 @@ switch(type)
}
else
OP2(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_UNUSED, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTEOL);
- add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO32));
+ add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO));
check_partial(common, FALSE);
jump[0] = JUMP(SLJIT_JUMP);
JUMPHERE(jump[1]);
@@ -8201,14 +8201,14 @@ switch(type)
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, begin));
add_jump(compiler, backtracks, CMP(SLJIT_GREATER, STR_PTR, 0, TMP1, 0));
OP2(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_UNUSED, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTBOL);
- add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO32));
+ add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO));
}
else
{
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, begin));
add_jump(compiler, backtracks, CMP(SLJIT_GREATER, STR_PTR, 0, TMP1, 0));
OP2(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_UNUSED, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTBOL);
- add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO32));
+ add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO));
}
return cc;
@@ -8227,7 +8227,7 @@ switch(type)
jump[1] = CMP(SLJIT_GREATER, STR_PTR, 0, TMP2, 0);
OP2(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_UNUSED, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTBOL);
}
- add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO32));
+ add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO));
jump[0] = JUMP(SLJIT_JUMP);
JUMPHERE(jump[1]);
@@ -9581,11 +9581,11 @@ free_stack(common, callout_arg_size);
/* Check return value. */
OP2(SLJIT_SUB32 | SLJIT_SET_Z | SLJIT_SET_SIG_GREATER, SLJIT_UNUSED, 0, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0);
-add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_SIG_GREATER32));
+add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_SIG_GREATER));
if (common->abort_label == NULL)
- add_jump(compiler, &common->abort, JUMP(SLJIT_NOT_EQUAL32) /* SIG_LESS */);
+ add_jump(compiler, &common->abort, JUMP(SLJIT_NOT_EQUAL) /* SIG_LESS */);
else
- JUMPTO(SLJIT_NOT_EQUAL32 /* SIG_LESS */, common->abort_label);
+ JUMPTO(SLJIT_NOT_EQUAL /* SIG_LESS */, common->abort_label);
return cc + callout_length;
}
@@ -11232,7 +11232,7 @@ early_fail_type = (early_fail_ptr & 0x7);
early_fail_ptr >>= 3;
/* During recursion, these optimizations are disabled. */
-if (common->early_fail_start_ptr == 0)
+if (common->early_fail_start_ptr == 0 && common->fast_forward_bc_ptr == NULL)
{
early_fail_ptr = 0;
early_fail_type = type_skip;
@@ -13661,9 +13661,11 @@ if (!common->private_data_ptrs)
memset(common->private_data_ptrs, 0, total_length * sizeof(sljit_s32));
private_data_size = common->cbra_ptr + (re->top_bracket + 1) * sizeof(sljit_sw);
-set_private_data_ptrs(common, &private_data_size, ccend);
+
if ((re->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);
+ detect_early_fail(common, common->start, &private_data_size, 0, 0, TRUE);
+
+set_private_data_ptrs(common, &private_data_size, ccend);
SLJIT_ASSERT(common->early_fail_start_ptr <= common->early_fail_end_ptr);
@@ -14130,6 +14132,10 @@ PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
pcre2_jit_compile(pcre2_code *code, uint32_t options)
{
pcre2_real_code *re = (pcre2_real_code *)code;
+#ifdef SUPPORT_JIT
+executable_functions *functions;
+static int executable_allocator_is_working = 0;
+#endif
if (code == NULL)
return PCRE2_ERROR_NULL;
@@ -14164,8 +14170,7 @@ actions are needed:
*/
#ifdef SUPPORT_JIT
-executable_functions *functions = (executable_functions *)re->executable_jit;
-static int executable_allocator_is_working = 0;
+functions = (executable_functions *)re->executable_jit;
#endif
if ((options & PCRE2_JIT_INVALID_UTF) != 0)
diff --git a/thirdparty/pcre2/src/pcre2_jit_simd_inc.h b/thirdparty/pcre2/src/pcre2_jit_simd_inc.h
index 5673d338c0..aa029cce38 100644
--- a/thirdparty/pcre2/src/pcre2_jit_simd_inc.h
+++ b/thirdparty/pcre2/src/pcre2_jit_simd_inc.h
@@ -39,7 +39,29 @@ POSSIBILITY OF SUCH DAMAGE.
-----------------------------------------------------------------------------
*/
-#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) && !(defined SUPPORT_VALGRIND)
+#if !(defined SUPPORT_VALGRIND)
+
+#if ((defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) \
+ || (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X))
+
+typedef enum {
+ vector_compare_match1,
+ vector_compare_match1i,
+ vector_compare_match2,
+} vector_compare_type;
+
+static SLJIT_INLINE sljit_u32 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
+}
#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)
@@ -56,6 +78,10 @@ return CMP(SLJIT_NOT_EQUAL, reg, 0, SLJIT_IMM, 0xdc00);
}
#endif
+#endif /* SLJIT_CONFIG_X86 || SLJIT_CONFIG_S390X */
+
+#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
+
static sljit_s32 character_to_int32(PCRE2_UCHAR chr)
{
sljit_u32 value = chr;
@@ -97,13 +123,7 @@ instruction[4] = (sljit_u8)offset;
sljit_emit_op_custom(compiler, instruction, 5);
}
-typedef enum {
- sse2_compare_match1,
- sse2_compare_match1i,
- sse2_compare_match2,
-} sse2_compare_type;
-
-static void fast_forward_char_pair_sse2_compare(struct sljit_compiler *compiler, sse2_compare_type compare_type,
+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];
@@ -112,11 +132,11 @@ instruction[1] = 0x0f;
SLJIT_ASSERT(step >= 0 && step <= 3);
-if (compare_type != sse2_compare_match2)
+if (compare_type != vector_compare_match2)
{
if (step == 0)
{
- if (compare_type == sse2_compare_match1i)
+ if (compare_type == vector_compare_match1i)
{
/* POR xmm1, xmm2/m128 */
/* instruction[0] = 0x66; */
@@ -185,14 +205,14 @@ switch (step)
static void fast_forward_char_simd(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2, sljit_s32 offset)
{
DEFINE_COMPILER;
+sljit_u8 instruction[8];
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];
-sse2_compare_type compare_type = sse2_compare_match1;
-sljit_u8 instruction[8];
+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;
@@ -207,12 +227,12 @@ SLJIT_UNUSED_ARG(offset);
if (char1 != char2)
{
bit = char1 ^ char2;
- compare_type = sse2_compare_match1i;
+ compare_type = vector_compare_match1i;
if (!is_powerof2(bit))
{
bit = 0;
- compare_type = sse2_compare_match2;
+ compare_type = vector_compare_match2;
}
}
@@ -349,11 +369,11 @@ if (common->utf && offset > 0)
static jump_list *fast_requested_char_simd(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2)
{
DEFINE_COMPILER;
+sljit_u8 instruction[8];
struct sljit_label *start;
struct sljit_jump *quit;
jump_list *not_found = NULL;
-sse2_compare_type compare_type = sse2_compare_match1;
-sljit_u8 instruction[8];
+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;
@@ -366,12 +386,12 @@ int i;
if (char1 != char2)
{
bit = char1 ^ char2;
- compare_type = sse2_compare_match1i;
+ compare_type = vector_compare_match1i;
if (!is_powerof2(bit))
{
bit = 0;
- compare_type = sse2_compare_match2;
+ compare_type = vector_compare_match2;
}
}
@@ -476,27 +496,15 @@ return not_found;
#ifndef _WIN64
-static SLJIT_INLINE sljit_u32 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
-}
-
#define JIT_HAS_FAST_FORWARD_CHAR_PAIR_SIMD (sljit_has_cpu_feature(SLJIT_HAS_SSE2))
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;
-sse2_compare_type compare1_type = sse2_compare_match1;
-sse2_compare_type compare2_type = sse2_compare_match1;
+sljit_u8 instruction[8];
+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);
@@ -516,7 +524,6 @@ struct sljit_label *start;
struct sljit_label *restart;
#endif
struct sljit_jump *jump[2];
-sljit_u8 instruction[8];
int i;
SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE && offs1 > offs2);
@@ -549,13 +556,13 @@ else
bit1 = char1a ^ char1b;
if (is_powerof2(bit1))
{
- compare1_type = sse2_compare_match1i;
+ compare1_type = vector_compare_match1i;
OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1a | bit1));
OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, character_to_int32(bit1));
}
else
{
- compare1_type = sse2_compare_match2;
+ compare1_type = vector_compare_match2;
bit1 = 0;
OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1a));
OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, character_to_int32(char1b));
@@ -578,13 +585,13 @@ else
bit2 = char2a ^ char2b;
if (is_powerof2(bit2))
{
- compare2_type = sse2_compare_match1i;
+ compare2_type = vector_compare_match1i;
OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char2a | bit2));
OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, character_to_int32(bit2));
}
else
{
- compare2_type = sse2_compare_match2;
+ compare2_type = vector_compare_match2;
bit2 = 0;
OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char2a));
OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, character_to_int32(char2b));
@@ -731,9 +738,6 @@ 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 (common->match_end_ptr != 0)
- OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr);
-
#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
if (common->utf)
{
@@ -760,7 +764,7 @@ if (common->match_end_ptr != 0)
#undef SSE2_COMPARE_TYPE_INDEX
-#endif /* SLJIT_CONFIG_X86 && !SUPPORT_VALGRIND */
+#endif /* SLJIT_CONFIG_X86 */
#if (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64 && (defined __ARM_NEON || defined __ARM_NEON__))
@@ -1121,3 +1125,734 @@ JUMPHERE(partial_quit);
}
#endif /* SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64 */
+
+#if (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X)
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+#define VECTOR_ELEMENT_SIZE 0
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+#define VECTOR_ELEMENT_SIZE 1
+#elif PCRE2_CODE_UNIT_WIDTH == 32
+#define VECTOR_ELEMENT_SIZE 2
+#else
+#error "Unsupported unit width"
+#endif
+
+static void load_from_mem_vector(struct sljit_compiler *compiler, BOOL vlbb, sljit_s32 dst_vreg,
+ sljit_s32 base_reg, sljit_s32 index_reg)
+{
+sljit_u16 instruction[3];
+
+instruction[0] = (sljit_u16)(0xe700 | (dst_vreg << 4) | index_reg);
+instruction[1] = (sljit_u16)(base_reg << 12);
+instruction[2] = (sljit_u16)((0x8 << 8) | (vlbb ? 0x07 : 0x06));
+
+sljit_emit_op_custom(compiler, instruction, 6);
+}
+
+#if PCRE2_CODE_UNIT_WIDTH == 32
+
+static void replicate_imm_vector(struct sljit_compiler *compiler, int step, sljit_s32 dst_vreg,
+ PCRE2_UCHAR chr, sljit_s32 tmp_general_reg)
+{
+sljit_u16 instruction[3];
+
+SLJIT_ASSERT(step >= 0 && step <= 1);
+
+if (chr < 0x7fff)
+ {
+ if (step == 1)
+ return;
+
+ /* VREPI */
+ instruction[0] = (sljit_u16)(0xe700 | (dst_vreg << 4));
+ instruction[1] = (sljit_u16)chr;
+ instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0x8 << 8) | 0x45);
+ sljit_emit_op_custom(compiler, instruction, 6);
+ return;
+ }
+
+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[1] = 0;
+ instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0x8 << 8) | 0x22);
+ sljit_emit_op_custom(compiler, instruction, 6);
+ return;
+ }
+
+/* VREP */
+instruction[0] = (sljit_u16)(0xe700 | (dst_vreg << 4) | dst_vreg);
+instruction[1] = 0;
+instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0xc << 8) | 0x4d);
+sljit_emit_op_custom(compiler, instruction, 6);
+}
+
+#endif
+
+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_u16 instruction[3];
+
+SLJIT_ASSERT(step >= 0 && step <= 2);
+
+if (step == 1)
+ {
+ /* VCEQ */
+ instruction[0] = (sljit_u16)(0xe700 | (dst_ind << 4) | dst_ind);
+ instruction[1] = (sljit_u16)(cmp1_ind << 12);
+ instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0xe << 8) | 0xf8);
+ sljit_emit_op_custom(compiler, instruction, 6);
+ return;
+ }
+
+if (compare_type != vector_compare_match2)
+ {
+ if (step == 0 && compare_type == vector_compare_match1i)
+ {
+ /* VO */
+ instruction[0] = (sljit_u16)(0xe700 | (dst_ind << 4) | dst_ind);
+ instruction[1] = (sljit_u16)(cmp2_ind << 12);
+ instruction[2] = (sljit_u16)((0xe << 8) | 0x6a);
+ sljit_emit_op_custom(compiler, instruction, 6);
+ }
+ return;
+ }
+
+switch (step)
+ {
+ case 0:
+ /* VCEQ */
+ instruction[0] = (sljit_u16)(0xe700 | (tmp_ind << 4) | dst_ind);
+ instruction[1] = (sljit_u16)(cmp2_ind << 12);
+ instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0xe << 8) | 0xf8);
+ sljit_emit_op_custom(compiler, instruction, 6);
+ return;
+
+ case 2:
+ /* VO */
+ instruction[0] = (sljit_u16)(0xe700 | (dst_ind << 4) | dst_ind);
+ instruction[1] = (sljit_u16)(tmp_ind << 12);
+ instruction[2] = (sljit_u16)((0xe << 8) | 0x6a);
+ sljit_emit_op_custom(compiler, instruction, 6);
+ return;
+ }
+}
+
+#define JIT_HAS_FAST_FORWARD_CHAR_SIMD 1
+
+static void fast_forward_char_simd(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2, sljit_s32 offset)
+{
+DEFINE_COMPILER;
+sljit_u16 instruction[3];
+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(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 zero_ind = 4;
+sljit_u32 bit = 0;
+int i;
+
+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) */
+
+OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, 16);
+
+#if PCRE2_CODE_UNIT_WIDTH != 32
+
+/* VREPI */
+instruction[0] = (sljit_u16)(0xe700 | (cmp1_ind << 4));
+instruction[1] = (sljit_u16)(char1 | bit);
+instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0x8 << 8) | 0x45);
+sljit_emit_op_custom(compiler, instruction, 6);
+
+if (char1 != char2)
+ {
+ /* VREPI */
+ instruction[0] = (sljit_u16)(0xe700 | (cmp2_ind << 4));
+ instruction[1] = (sljit_u16)(bit != 0 ? bit : char2);
+ /* instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0x8 << 8) | 0x45); */
+ sljit_emit_op_custom(compiler, instruction, 6);
+ }
+
+#else /* PCRE2_CODE_UNIT_WIDTH == 32 */
+
+for (int i = 0; i < 2; i++)
+ {
+ replicate_imm_vector(compiler, i, cmp1_ind, char1 | bit, TMP1);
+
+ if (char1 != char2)
+ replicate_imm_vector(compiler, i, cmp2_ind, bit != 0 ? bit : char2, TMP1);
+ }
+
+#endif /* PCRE2_CODE_UNIT_WIDTH != 32 */
+
+if (compare_type == vector_compare_match2)
+ {
+ /* VREPI */
+ instruction[0] = (sljit_u16)(0xe700 | (zero_ind << 4));
+ instruction[1] = 0;
+ instruction[2] = (sljit_u16)((0x8 << 8) | 0x45);
+ sljit_emit_op_custom(compiler, instruction, 6);
+ }
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+restart = LABEL();
+#endif
+
+load_from_mem_vector(compiler, TRUE, data_ind, str_ptr_reg_ind, 0);
+OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, ~15);
+
+if (compare_type != vector_compare_match2)
+ {
+ if (compare_type == vector_compare_match1i)
+ fast_forward_char_pair_sse2_compare(compiler, compare_type, 0, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
+
+ /* VFEE */
+ instruction[0] = (sljit_u16)(0xe700 | (data_ind << 4) | data_ind);
+ instruction[1] = (sljit_u16)((cmp1_ind << 12) | (1 << 4));
+ instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0xe << 8) | 0x80);
+ sljit_emit_op_custom(compiler, instruction, 6);
+ }
+else
+ {
+ for (i = 0; i < 3; i++)
+ fast_forward_char_pair_sse2_compare(compiler, compare_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
+
+ /* VFENE */
+ instruction[0] = (sljit_u16)(0xe700 | (data_ind << 4) | data_ind);
+ instruction[1] = (sljit_u16)((zero_ind << 12) | (1 << 4));
+ instruction[2] = (sljit_u16)((0xe << 8) | 0x81);
+ sljit_emit_op_custom(compiler, instruction, 6);
+ }
+
+/* VLGVB */
+instruction[0] = (sljit_u16)(0xe700 | (tmp1_reg_ind << 4) | data_ind);
+instruction[1] = 7;
+instruction[2] = (sljit_u16)((0x4 << 8) | 0x21);
+sljit_emit_op_custom(compiler, instruction, 6);
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+quit = CMP(SLJIT_LESS, STR_PTR, 0, TMP2, 0);
+
+OP2(SLJIT_SUB, STR_PTR, 0, TMP2, 0, SLJIT_IMM, 16);
+
+/* 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]);
+
+load_from_mem_vector(compiler, TRUE, data_ind, str_ptr_reg_ind, 0);
+
+if (compare_type != vector_compare_match2)
+ {
+ if (compare_type == vector_compare_match1i)
+ fast_forward_char_pair_sse2_compare(compiler, compare_type, 0, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
+
+ /* VFEE */
+ instruction[0] = (sljit_u16)(0xe700 | (data_ind << 4) | data_ind);
+ instruction[1] = (sljit_u16)((cmp1_ind << 12) | (1 << 4));
+ instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0xe << 8) | 0x80);
+ sljit_emit_op_custom(compiler, instruction, 6);
+ }
+else
+ {
+ for (i = 0; i < 3; i++)
+ fast_forward_char_pair_sse2_compare(compiler, compare_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
+
+ /* VFENE */
+ instruction[0] = (sljit_u16)(0xe700 | (data_ind << 4) | data_ind);
+ instruction[1] = (sljit_u16)((zero_ind << 12) | (1 << 4));
+ instruction[2] = (sljit_u16)((0xe << 8) | 0x81);
+ sljit_emit_op_custom(compiler, instruction, 6);
+ }
+
+sljit_set_current_flags(compiler, SLJIT_SET_OVERFLOW);
+JUMPTO(SLJIT_OVERFLOW, start);
+
+/* VLGVB */
+instruction[0] = (sljit_u16)(0xe700 | (tmp1_reg_ind << 4) | data_ind);
+instruction[1] = 7;
+instruction[2] = (sljit_u16)((0x4 << 8) | 0x21);
+sljit_emit_op_custom(compiler, instruction, 6);
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+
+JUMPHERE(quit);
+
+if (common->mode != PCRE2_JIT_COMPLETE)
+ {
+ JUMPHERE(partial_quit[0]);
+ JUMPHERE(partial_quit[1]);
+ OP2(SLJIT_SUB | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, STR_PTR, 0, STR_END, 0);
+ CMOV(SLJIT_GREATER, STR_PTR, STR_END, 0);
+ }
+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));
+
+ OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, 16);
+ JUMPTO(SLJIT_JUMP, restart);
+
+ JUMPHERE(quit);
+ }
+#endif
+}
+
+#define JIT_HAS_FAST_REQUESTED_CHAR_SIMD 1
+
+static jump_list *fast_requested_char_simd(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2)
+{
+DEFINE_COMPILER;
+sljit_u16 instruction[3];
+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 data_ind = 0;
+sljit_s32 tmp_ind = 1;
+sljit_s32 cmp1_ind = 2;
+sljit_s32 cmp2_ind = 3;
+sljit_s32 zero_ind = 4;
+sljit_u32 bit = 0;
+int i;
+
+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));
+
+/* First part (unaligned start) */
+
+OP2(SLJIT_ADD, TMP2, 0, TMP1, 0, SLJIT_IMM, 16);
+
+#if PCRE2_CODE_UNIT_WIDTH != 32
+
+/* VREPI */
+instruction[0] = (sljit_u16)(0xe700 | (cmp1_ind << 4));
+instruction[1] = (sljit_u16)(char1 | bit);
+instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0x8 << 8) | 0x45);
+sljit_emit_op_custom(compiler, instruction, 6);
+
+if (char1 != char2)
+ {
+ /* VREPI */
+ instruction[0] = (sljit_u16)(0xe700 | (cmp2_ind << 4));
+ instruction[1] = (sljit_u16)(bit != 0 ? bit : char2);
+ /* instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0x8 << 8) | 0x45); */
+ sljit_emit_op_custom(compiler, instruction, 6);
+ }
+
+#else /* PCRE2_CODE_UNIT_WIDTH == 32 */
+
+for (int i = 0; i < 2; i++)
+ {
+ replicate_imm_vector(compiler, i, cmp1_ind, char1 | bit, TMP3);
+
+ if (char1 != char2)
+ replicate_imm_vector(compiler, i, cmp2_ind, bit != 0 ? bit : char2, TMP3);
+ }
+
+#endif /* PCRE2_CODE_UNIT_WIDTH != 32 */
+
+if (compare_type == vector_compare_match2)
+ {
+ /* VREPI */
+ instruction[0] = (sljit_u16)(0xe700 | (zero_ind << 4));
+ instruction[1] = 0;
+ instruction[2] = (sljit_u16)((0x8 << 8) | 0x45);
+ sljit_emit_op_custom(compiler, instruction, 6);
+ }
+
+load_from_mem_vector(compiler, TRUE, data_ind, tmp1_reg_ind, 0);
+OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, ~15);
+
+if (compare_type != vector_compare_match2)
+ {
+ if (compare_type == vector_compare_match1i)
+ fast_forward_char_pair_sse2_compare(compiler, compare_type, 0, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
+
+ /* VFEE */
+ instruction[0] = (sljit_u16)(0xe700 | (data_ind << 4) | data_ind);
+ instruction[1] = (sljit_u16)((cmp1_ind << 12) | (1 << 4));
+ instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0xe << 8) | 0x80);
+ sljit_emit_op_custom(compiler, instruction, 6);
+ }
+else
+ {
+ for (i = 0; i < 3; i++)
+ fast_forward_char_pair_sse2_compare(compiler, compare_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
+
+ /* VFENE */
+ instruction[0] = (sljit_u16)(0xe700 | (data_ind << 4) | data_ind);
+ instruction[1] = (sljit_u16)((zero_ind << 12) | (1 << 4));
+ instruction[2] = (sljit_u16)((0xe << 8) | 0x81);
+ sljit_emit_op_custom(compiler, instruction, 6);
+ }
+
+/* VLGVB */
+instruction[0] = (sljit_u16)(0xe700 | (tmp3_reg_ind << 4) | data_ind);
+instruction[1] = 7;
+instruction[2] = (sljit_u16)((0x4 << 8) | 0x21);
+sljit_emit_op_custom(compiler, instruction, 6);
+
+OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP3, 0);
+quit = CMP(SLJIT_LESS, TMP1, 0, TMP2, 0);
+
+OP2(SLJIT_SUB, TMP1, 0, TMP2, 0, SLJIT_IMM, 16);
+
+/* Second part (aligned) */
+start = LABEL();
+
+OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 16);
+
+add_jump(compiler, &not_found, CMP(SLJIT_GREATER_EQUAL, TMP1, 0, STR_END, 0));
+
+load_from_mem_vector(compiler, TRUE, data_ind, tmp1_reg_ind, 0);
+
+if (compare_type != vector_compare_match2)
+ {
+ if (compare_type == vector_compare_match1i)
+ fast_forward_char_pair_sse2_compare(compiler, compare_type, 0, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
+
+ /* VFEE */
+ instruction[0] = (sljit_u16)(0xe700 | (data_ind << 4) | data_ind);
+ instruction[1] = (sljit_u16)((cmp1_ind << 12) | (1 << 4));
+ instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0xe << 8) | 0x80);
+ sljit_emit_op_custom(compiler, instruction, 6);
+ }
+else
+ {
+ for (i = 0; i < 3; i++)
+ fast_forward_char_pair_sse2_compare(compiler, compare_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
+
+ /* VFENE */
+ instruction[0] = (sljit_u16)(0xe700 | (data_ind << 4) | data_ind);
+ instruction[1] = (sljit_u16)((zero_ind << 12) | (1 << 4));
+ instruction[2] = (sljit_u16)((0xe << 8) | 0x81);
+ sljit_emit_op_custom(compiler, instruction, 6);
+ }
+
+sljit_set_current_flags(compiler, SLJIT_SET_OVERFLOW);
+JUMPTO(SLJIT_OVERFLOW, start);
+
+/* VLGVB */
+instruction[0] = (sljit_u16)(0xe700 | (tmp3_reg_ind << 4) | data_ind);
+instruction[1] = 7;
+instruction[2] = (sljit_u16)((0x4 << 8) | 0x21);
+sljit_emit_op_custom(compiler, instruction, 6);
+
+OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP3, 0);
+
+JUMPHERE(quit);
+add_jump(compiler, &not_found, CMP(SLJIT_GREATER_EQUAL, TMP1, 0, STR_END, 0));
+
+return not_found;
+}
+
+#define JIT_HAS_FAST_FORWARD_CHAR_PAIR_SIMD 1
+
+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_u16 instruction[3];
+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 *jump[2];
+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_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 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 zero_ind = 8;
+int i;
+
+SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE && offs1 > offs2);
+SLJIT_ASSERT(-diff <= (sljit_s32)IN_UCHARS(max_fast_forward_char_pair_offset()));
+SLJIT_ASSERT(tmp1_reg_ind != 0 && tmp2_reg_ind != 0);
+
+if (char1a != char1b)
+ {
+ bit1 = char1a ^ char1b;
+ compare1_type = vector_compare_match1i;
+
+ if (!is_powerof2(bit1))
+ {
+ bit1 = 0;
+ compare1_type = vector_compare_match2;
+ }
+ }
+
+if (char2a != char2b)
+ {
+ bit2 = char2a ^ char2b;
+ compare2_type = vector_compare_match1i;
+
+ if (!is_powerof2(bit2))
+ {
+ bit2 = 0;
+ compare2_type = vector_compare_match2;
+ }
+ }
+
+/* Initialize. */
+if (common->match_end_ptr != 0)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr);
+ OP1(SLJIT_MOV, TMP3, 0, STR_END, 0);
+ OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(offs1 + 1));
+
+ OP2(SLJIT_SUB | SLJIT_SET_LESS, SLJIT_UNUSED, 0, TMP1, 0, STR_END, 0);
+ CMOV(SLJIT_LESS, STR_END, TMP1, 0);
+ }
+
+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));
+OP2(SLJIT_AND, TMP2, 0, STR_PTR, 0, SLJIT_IMM, ~15);
+
+#if PCRE2_CODE_UNIT_WIDTH != 32
+
+OP2(SLJIT_SUB, TMP1, 0, STR_PTR, 0, SLJIT_IMM, -diff);
+
+/* VREPI */
+instruction[0] = (sljit_u16)(0xe700 | (cmp1a_ind << 4));
+instruction[1] = (sljit_u16)(char1a | bit1);
+instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0x8 << 8) | 0x45);
+sljit_emit_op_custom(compiler, instruction, 6);
+
+if (char1a != char1b)
+ {
+ /* VREPI */
+ instruction[0] = (sljit_u16)(0xe700 | (cmp1b_ind << 4));
+ instruction[1] = (sljit_u16)(bit1 != 0 ? bit1 : char1b);
+ /* instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0x8 << 8) | 0x45); */
+ sljit_emit_op_custom(compiler, instruction, 6);
+ }
+
+/* VREPI */
+instruction[0] = (sljit_u16)(0xe700 | (cmp2a_ind << 4));
+instruction[1] = (sljit_u16)(char2a | bit2);
+/* instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0x8 << 8) | 0x45); */
+sljit_emit_op_custom(compiler, instruction, 6);
+
+if (char2a != char2b)
+ {
+ /* VREPI */
+ instruction[0] = (sljit_u16)(0xe700 | (cmp2b_ind << 4));
+ instruction[1] = (sljit_u16)(bit2 != 0 ? bit2 : char2b);
+ /* instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0x8 << 8) | 0x45); */
+ sljit_emit_op_custom(compiler, instruction, 6);
+ }
+
+#else /* PCRE2_CODE_UNIT_WIDTH == 32 */
+
+for (int i = 0; i < 2; i++)
+ {
+ replicate_imm_vector(compiler, i, cmp1a_ind, char1a | bit1, TMP1);
+
+ if (char1a != char1b)
+ replicate_imm_vector(compiler, i, cmp1b_ind, bit1 != 0 ? bit1 : char1b, TMP1);
+
+ replicate_imm_vector(compiler, i, cmp2a_ind, char2a | bit2, TMP1);
+
+ if (char2a != char2b)
+ replicate_imm_vector(compiler, i, cmp2b_ind, bit2 != 0 ? bit2 : char2b, TMP1);
+ }
+
+OP2(SLJIT_SUB, TMP1, 0, STR_PTR, 0, SLJIT_IMM, -diff);
+
+#endif /* PCRE2_CODE_UNIT_WIDTH != 32 */
+
+/* VREPI */
+instruction[0] = (sljit_u16)(0xe700 | (zero_ind << 4));
+instruction[1] = 0;
+instruction[2] = (sljit_u16)((0x8 << 8) | 0x45);
+sljit_emit_op_custom(compiler, instruction, 6);
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+restart = LABEL();
+#endif
+
+jump[0] = CMP(SLJIT_LESS, TMP1, 0, TMP2, 0);
+load_from_mem_vector(compiler, TRUE, data2_ind, tmp1_reg_ind, 0);
+jump[1] = JUMP(SLJIT_JUMP);
+JUMPHERE(jump[0]);
+load_from_mem_vector(compiler, FALSE, data2_ind, tmp1_reg_ind, 0);
+JUMPHERE(jump[1]);
+
+load_from_mem_vector(compiler, TRUE, data1_ind, str_ptr_reg_ind, 0);
+OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, 16);
+
+for (i = 0; i < 3; i++)
+ {
+ 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, i, data2_ind, cmp2a_ind, cmp2b_ind, tmp2_ind);
+ }
+
+/* VN */
+instruction[0] = (sljit_u16)(0xe700 | (data1_ind << 4) | data1_ind);
+instruction[1] = (sljit_u16)(data2_ind << 12);
+instruction[2] = (sljit_u16)((0xe << 8) | 0x68);
+sljit_emit_op_custom(compiler, instruction, 6);
+
+/* VFENE */
+instruction[0] = (sljit_u16)(0xe700 | (data1_ind << 4) | data1_ind);
+instruction[1] = (sljit_u16)((zero_ind << 12) | (1 << 4));
+instruction[2] = (sljit_u16)((0xe << 8) | 0x81);
+sljit_emit_op_custom(compiler, instruction, 6);
+
+/* VLGVB */
+instruction[0] = (sljit_u16)(0xe700 | (tmp1_reg_ind << 4) | data1_ind);
+instruction[1] = 7;
+instruction[2] = (sljit_u16)((0x4 << 8) | 0x21);
+sljit_emit_op_custom(compiler, instruction, 6);
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+quit = CMP(SLJIT_LESS, STR_PTR, 0, TMP2, 0);
+
+OP2(SLJIT_SUB, STR_PTR, 0, TMP2, 0, SLJIT_IMM, 16);
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, diff);
+
+/* 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));
+
+load_from_mem_vector(compiler, FALSE, data1_ind, str_ptr_reg_ind, 0);
+load_from_mem_vector(compiler, FALSE, data2_ind, str_ptr_reg_ind, tmp1_reg_ind);
+
+for (i = 0; i < 3; i++)
+ {
+ 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, i, data2_ind, cmp2a_ind, cmp2b_ind, tmp2_ind);
+ }
+
+/* VN */
+instruction[0] = (sljit_u16)(0xe700 | (data1_ind << 4) | data1_ind);
+instruction[1] = (sljit_u16)(data2_ind << 12);
+instruction[2] = (sljit_u16)((0xe << 8) | 0x68);
+sljit_emit_op_custom(compiler, instruction, 6);
+
+/* VFENE */
+instruction[0] = (sljit_u16)(0xe700 | (data1_ind << 4) | data1_ind);
+instruction[1] = (sljit_u16)((zero_ind << 12) | (1 << 4));
+instruction[2] = (sljit_u16)((0xe << 8) | 0x81);
+sljit_emit_op_custom(compiler, instruction, 6);
+
+sljit_set_current_flags(compiler, SLJIT_SET_OVERFLOW);
+JUMPTO(SLJIT_OVERFLOW, start);
+
+/* VLGVB */
+instruction[0] = (sljit_u16)(0xe700 | (tmp2_reg_ind << 4) | data1_ind);
+instruction[1] = 7;
+instruction[2] = (sljit_u16)((0x4 << 8) | 0x21);
+sljit_emit_op_custom(compiler, instruction, 6);
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+
+JUMPHERE(quit);
+
+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)
+ {
+ SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE);
+
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-offs1));
+
+ 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));
+
+ /* TMP1 contains diff. */
+ OP2(SLJIT_AND, TMP2, 0, STR_PTR, 0, SLJIT_IMM, ~15);
+ OP2(SLJIT_SUB, TMP1, 0, STR_PTR, 0, SLJIT_IMM, -diff);
+ JUMPTO(SLJIT_JUMP, restart);
+
+ JUMPHERE(quit);
+ }
+#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_S390X */
+
+#endif /* !SUPPORT_VALGRIND */
diff --git a/thirdparty/pcre2/src/pcre2_match.c b/thirdparty/pcre2/src/pcre2_match.c
index e3f78c2ca3..f28cdbb47a 100644
--- a/thirdparty/pcre2/src/pcre2_match.c
+++ b/thirdparty/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-2020 University of Cambridge
+ New API code Copyright (c) 2015-2021 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -818,10 +818,12 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
/* N is now the frame of the recursion; the previous frame is at the
OP_RECURSE position. Go back there, copying the current subject position
- and mark, and move on past the OP_RECURSE. */
+ and mark, and the start_match position (\K might have changed it), and
+ then move on past the OP_RECURSE. */
P->eptr = Feptr;
P->mark = Fmark;
+ P->start_match = Fstart_match;
F = P;
Fecode += 1 + LINK_SIZE;
continue;
@@ -6115,8 +6117,8 @@ BOOL has_req_cu = FALSE;
BOOL startline;
#if PCRE2_CODE_UNIT_WIDTH == 8
-BOOL memchr_not_found_first_cu;
-BOOL memchr_not_found_first_cu2;
+PCRE2_SPTR memchr_found_first_cu;
+PCRE2_SPTR memchr_found_first_cu2;
#endif
PCRE2_UCHAR first_cu = 0;
@@ -6710,8 +6712,8 @@ start_partial = match_partial = NULL;
mb->hitend = FALSE;
#if PCRE2_CODE_UNIT_WIDTH == 8
-memchr_not_found_first_cu = FALSE;
-memchr_not_found_first_cu2 = FALSE;
+memchr_found_first_cu = NULL;
+memchr_found_first_cu2 = NULL;
#endif
for(;;)
@@ -6780,13 +6782,7 @@ for(;;)
}
}
- /* Not anchored. Advance to a unique first code unit if there is one. In
- 8-bit mode, the use of memchr() gives a big speed up, even though we have
- to call it twice in caseless mode, in order to find the earliest occurrence
- of the character in either of its cases. If a call to memchr() that
- searches the rest of the subject fails to find one case, remember that in
- order not to keep on repeating the search. This can make a huge difference
- when the strings are very long and only one case is present. */
+ /* Not anchored. Advance to a unique first code unit if there is one. */
else
{
@@ -6794,43 +6790,68 @@ for(;;)
{
if (first_cu != first_cu2) /* Caseless */
{
+ /* In 16-bit and 32_bit modes we have to do our own search, so can
+ look for both cases at once. */
+
#if PCRE2_CODE_UNIT_WIDTH != 8
PCRE2_UCHAR smc;
while (start_match < end_subject &&
(smc = UCHAR21TEST(start_match)) != first_cu &&
- smc != first_cu2)
+ smc != first_cu2)
start_match++;
+#else
+ /* In 8-bit mode, the use of memchr() gives a big speed up, even
+ though we have to call it twice in order to find the earliest
+ occurrence of the code unit in either of its cases. Caching is used
+ to remember the positions of previously found code units. This can
+ make a huge difference when the strings are very long and only one
+ case is actually present. */
-#else /* 8-bit code units */
PCRE2_SPTR pp1 = NULL;
PCRE2_SPTR pp2 = NULL;
- PCRE2_SIZE cu2size = end_subject - start_match;
+ PCRE2_SIZE searchlength = end_subject - start_match;
- if (!memchr_not_found_first_cu)
+ /* If we haven't got a previously found position for first_cu, or if
+ the current starting position is later, we need to do a search. If
+ the code unit is not found, set it to the end. */
+
+ if (memchr_found_first_cu == NULL ||
+ start_match > memchr_found_first_cu)
{
- pp1 = memchr(start_match, first_cu, end_subject - start_match);
- if (pp1 == NULL) memchr_not_found_first_cu = TRUE;
- else cu2size = pp1 - start_match;
+ pp1 = memchr(start_match, first_cu, searchlength);
+ memchr_found_first_cu = (pp1 == NULL)? end_subject : pp1;
}
- /* If pp1 is not NULL, we have arranged to search only as far as pp1,
- to see if the other case is earlier, so we can set "not found" only
- when both searches have returned NULL. */
+ /* If the start is before a previously found position, use the
+ previous position, or NULL if a previous search failed. */
+
+ else pp1 = (memchr_found_first_cu == end_subject)? NULL :
+ memchr_found_first_cu;
- if (!memchr_not_found_first_cu2)
+ /* Do the same thing for the other case. */
+
+ if (memchr_found_first_cu2 == NULL ||
+ start_match > memchr_found_first_cu2)
{
- pp2 = memchr(start_match, first_cu2, cu2size);
- memchr_not_found_first_cu2 = (pp2 == NULL && pp1 == NULL);
+ pp2 = memchr(start_match, first_cu2, searchlength);
+ memchr_found_first_cu2 = (pp2 == NULL)? end_subject : pp2;
}
+ else pp2 = (memchr_found_first_cu2 == end_subject)? NULL :
+ memchr_found_first_cu2;
+
+ /* Set the start to the end of the subject if neither case was found.
+ Otherwise, use the earlier found point. */
+
if (pp1 == NULL)
start_match = (pp2 == NULL)? end_subject : pp2;
else
start_match = (pp2 == NULL || pp1 < pp2)? pp1 : pp2;
-#endif
+
+#endif /* 8-bit handling */
}
- /* The caseful case */
+ /* The caseful case is much simpler. */
else
{
diff --git a/thirdparty/pcre2/src/pcre2_tables.c b/thirdparty/pcre2/src/pcre2_tables.c
index b10de45efb..c164e976e0 100644
--- a/thirdparty/pcre2/src/pcre2_tables.c
+++ b/thirdparty/pcre2/src/pcre2_tables.c
@@ -273,6 +273,7 @@ strings to make sure that UTF-8 support works on EBCDIC platforms. */
#define STRING_Cs0 STR_C STR_s "\0"
#define STRING_Cuneiform0 STR_C STR_u STR_n STR_e STR_i STR_f STR_o STR_r STR_m "\0"
#define STRING_Cypriot0 STR_C STR_y STR_p STR_r STR_i STR_o STR_t "\0"
+#define STRING_Cypro_Minoan0 STR_C STR_y STR_p STR_r STR_o STR_UNDERSCORE STR_M STR_i STR_n STR_o STR_a STR_n "\0"
#define STRING_Cyrillic0 STR_C STR_y STR_r STR_i STR_l STR_l STR_i STR_c "\0"
#define STRING_Deseret0 STR_D STR_e STR_s STR_e STR_r STR_e STR_t "\0"
#define STRING_Devanagari0 STR_D STR_e STR_v STR_a STR_n STR_a STR_g STR_a STR_r STR_i "\0"
@@ -371,6 +372,7 @@ strings to make sure that UTF-8 support works on EBCDIC platforms. */
#define STRING_Old_Sogdian0 STR_O STR_l STR_d STR_UNDERSCORE STR_S STR_o STR_g STR_d STR_i STR_a STR_n "\0"
#define STRING_Old_South_Arabian0 STR_O STR_l STR_d STR_UNDERSCORE STR_S STR_o STR_u STR_t STR_h STR_UNDERSCORE STR_A STR_r STR_a STR_b STR_i STR_a STR_n "\0"
#define STRING_Old_Turkic0 STR_O STR_l STR_d STR_UNDERSCORE STR_T STR_u STR_r STR_k STR_i STR_c "\0"
+#define STRING_Old_Uyghur0 STR_O STR_l STR_d STR_UNDERSCORE STR_U STR_y STR_g STR_h STR_u STR_r "\0"
#define STRING_Oriya0 STR_O STR_r STR_i STR_y STR_a "\0"
#define STRING_Osage0 STR_O STR_s STR_a STR_g STR_e "\0"
#define STRING_Osmanya0 STR_O STR_s STR_m STR_a STR_n STR_y STR_a "\0"
@@ -415,6 +417,7 @@ strings to make sure that UTF-8 support works on EBCDIC platforms. */
#define STRING_Tai_Viet0 STR_T STR_a STR_i STR_UNDERSCORE STR_V STR_i STR_e STR_t "\0"
#define STRING_Takri0 STR_T STR_a STR_k STR_r STR_i "\0"
#define STRING_Tamil0 STR_T STR_a STR_m STR_i STR_l "\0"
+#define STRING_Tangsa0 STR_T STR_a STR_n STR_g STR_s STR_a "\0"
#define STRING_Tangut0 STR_T STR_a STR_n STR_g STR_u STR_t "\0"
#define STRING_Telugu0 STR_T STR_e STR_l STR_u STR_g STR_u "\0"
#define STRING_Thaana0 STR_T STR_h STR_a STR_a STR_n STR_a "\0"
@@ -422,9 +425,11 @@ strings to make sure that UTF-8 support works on EBCDIC platforms. */
#define STRING_Tibetan0 STR_T STR_i STR_b STR_e STR_t STR_a STR_n "\0"
#define STRING_Tifinagh0 STR_T STR_i STR_f STR_i STR_n STR_a STR_g STR_h "\0"
#define STRING_Tirhuta0 STR_T STR_i STR_r STR_h STR_u STR_t STR_a "\0"
+#define STRING_Toto0 STR_T STR_o STR_t STR_o "\0"
#define STRING_Ugaritic0 STR_U STR_g STR_a STR_r STR_i STR_t STR_i STR_c "\0"
#define STRING_Unknown0 STR_U STR_n STR_k STR_n STR_o STR_w STR_n "\0"
#define STRING_Vai0 STR_V STR_a STR_i "\0"
+#define STRING_Vithkuqi0 STR_V STR_i STR_t STR_h STR_k STR_u STR_q STR_i "\0"
#define STRING_Wancho0 STR_W STR_a STR_n STR_c STR_h STR_o "\0"
#define STRING_Warang_Citi0 STR_W STR_a STR_r STR_a STR_n STR_g STR_UNDERSCORE STR_C STR_i STR_t STR_i "\0"
#define STRING_Xan0 STR_X STR_a STR_n "\0"
@@ -476,6 +481,7 @@ const char PRIV(utt_names)[] =
STRING_Cs0
STRING_Cuneiform0
STRING_Cypriot0
+ STRING_Cypro_Minoan0
STRING_Cyrillic0
STRING_Deseret0
STRING_Devanagari0
@@ -574,6 +580,7 @@ const char PRIV(utt_names)[] =
STRING_Old_Sogdian0
STRING_Old_South_Arabian0
STRING_Old_Turkic0
+ STRING_Old_Uyghur0
STRING_Oriya0
STRING_Osage0
STRING_Osmanya0
@@ -618,6 +625,7 @@ const char PRIV(utt_names)[] =
STRING_Tai_Viet0
STRING_Takri0
STRING_Tamil0
+ STRING_Tangsa0
STRING_Tangut0
STRING_Telugu0
STRING_Thaana0
@@ -625,9 +633,11 @@ const char PRIV(utt_names)[] =
STRING_Tibetan0
STRING_Tifinagh0
STRING_Tirhuta0
+ STRING_Toto0
STRING_Ugaritic0
STRING_Unknown0
STRING_Vai0
+ STRING_Vithkuqi0
STRING_Wancho0
STRING_Warang_Citi0
STRING_Xan0
@@ -679,172 +689,177 @@ const ucp_type_table PRIV(utt)[] = {
{ 255, PT_PC, ucp_Cs },
{ 258, PT_SC, ucp_Cuneiform },
{ 268, PT_SC, ucp_Cypriot },
- { 276, PT_SC, ucp_Cyrillic },
- { 285, PT_SC, ucp_Deseret },
- { 293, PT_SC, ucp_Devanagari },
- { 304, PT_SC, ucp_Dives_Akuru },
- { 316, PT_SC, ucp_Dogra },
- { 322, PT_SC, ucp_Duployan },
- { 331, PT_SC, ucp_Egyptian_Hieroglyphs },
- { 352, PT_SC, ucp_Elbasan },
- { 360, PT_SC, ucp_Elymaic },
- { 368, PT_SC, ucp_Ethiopic },
- { 377, PT_SC, ucp_Georgian },
- { 386, PT_SC, ucp_Glagolitic },
- { 397, PT_SC, ucp_Gothic },
- { 404, PT_SC, ucp_Grantha },
- { 412, PT_SC, ucp_Greek },
- { 418, PT_SC, ucp_Gujarati },
- { 427, PT_SC, ucp_Gunjala_Gondi },
- { 441, PT_SC, ucp_Gurmukhi },
- { 450, PT_SC, ucp_Han },
- { 454, PT_SC, ucp_Hangul },
- { 461, PT_SC, ucp_Hanifi_Rohingya },
- { 477, PT_SC, ucp_Hanunoo },
- { 485, PT_SC, ucp_Hatran },
- { 492, PT_SC, ucp_Hebrew },
- { 499, PT_SC, ucp_Hiragana },
- { 508, PT_SC, ucp_Imperial_Aramaic },
- { 525, PT_SC, ucp_Inherited },
- { 535, PT_SC, ucp_Inscriptional_Pahlavi },
- { 557, PT_SC, ucp_Inscriptional_Parthian },
- { 580, PT_SC, ucp_Javanese },
- { 589, PT_SC, ucp_Kaithi },
- { 596, PT_SC, ucp_Kannada },
- { 604, PT_SC, ucp_Katakana },
- { 613, PT_SC, ucp_Kayah_Li },
- { 622, PT_SC, ucp_Kharoshthi },
- { 633, PT_SC, ucp_Khitan_Small_Script },
- { 653, PT_SC, ucp_Khmer },
- { 659, PT_SC, ucp_Khojki },
- { 666, PT_SC, ucp_Khudawadi },
- { 676, PT_GC, ucp_L },
- { 678, PT_LAMP, 0 },
- { 681, PT_SC, ucp_Lao },
- { 685, PT_SC, ucp_Latin },
- { 691, PT_SC, ucp_Lepcha },
- { 698, PT_SC, ucp_Limbu },
- { 704, PT_SC, ucp_Linear_A },
- { 713, PT_SC, ucp_Linear_B },
- { 722, PT_SC, ucp_Lisu },
- { 727, PT_PC, ucp_Ll },
- { 730, PT_PC, ucp_Lm },
- { 733, PT_PC, ucp_Lo },
- { 736, PT_PC, ucp_Lt },
- { 739, PT_PC, ucp_Lu },
- { 742, PT_SC, ucp_Lycian },
- { 749, PT_SC, ucp_Lydian },
- { 756, PT_GC, ucp_M },
- { 758, PT_SC, ucp_Mahajani },
- { 767, PT_SC, ucp_Makasar },
- { 775, PT_SC, ucp_Malayalam },
- { 785, PT_SC, ucp_Mandaic },
- { 793, PT_SC, ucp_Manichaean },
- { 804, PT_SC, ucp_Marchen },
- { 812, PT_SC, ucp_Masaram_Gondi },
- { 826, PT_PC, ucp_Mc },
- { 829, PT_PC, ucp_Me },
- { 832, PT_SC, ucp_Medefaidrin },
- { 844, PT_SC, ucp_Meetei_Mayek },
- { 857, PT_SC, ucp_Mende_Kikakui },
- { 871, PT_SC, ucp_Meroitic_Cursive },
- { 888, PT_SC, ucp_Meroitic_Hieroglyphs },
- { 909, PT_SC, ucp_Miao },
- { 914, PT_PC, ucp_Mn },
- { 917, PT_SC, ucp_Modi },
- { 922, PT_SC, ucp_Mongolian },
- { 932, PT_SC, ucp_Mro },
- { 936, PT_SC, ucp_Multani },
- { 944, PT_SC, ucp_Myanmar },
- { 952, PT_GC, ucp_N },
- { 954, PT_SC, ucp_Nabataean },
- { 964, PT_SC, ucp_Nandinagari },
- { 976, PT_PC, ucp_Nd },
- { 979, PT_SC, ucp_New_Tai_Lue },
- { 991, PT_SC, ucp_Newa },
- { 996, PT_SC, ucp_Nko },
- { 1000, PT_PC, ucp_Nl },
- { 1003, PT_PC, ucp_No },
- { 1006, PT_SC, ucp_Nushu },
- { 1012, PT_SC, ucp_Nyiakeng_Puachue_Hmong },
- { 1035, PT_SC, ucp_Ogham },
- { 1041, PT_SC, ucp_Ol_Chiki },
- { 1050, PT_SC, ucp_Old_Hungarian },
- { 1064, PT_SC, ucp_Old_Italic },
- { 1075, PT_SC, ucp_Old_North_Arabian },
- { 1093, PT_SC, ucp_Old_Permic },
- { 1104, PT_SC, ucp_Old_Persian },
- { 1116, PT_SC, ucp_Old_Sogdian },
- { 1128, PT_SC, ucp_Old_South_Arabian },
- { 1146, PT_SC, ucp_Old_Turkic },
- { 1157, PT_SC, ucp_Oriya },
- { 1163, PT_SC, ucp_Osage },
- { 1169, PT_SC, ucp_Osmanya },
- { 1177, PT_GC, ucp_P },
- { 1179, PT_SC, ucp_Pahawh_Hmong },
- { 1192, PT_SC, ucp_Palmyrene },
- { 1202, PT_SC, ucp_Pau_Cin_Hau },
- { 1214, PT_PC, ucp_Pc },
- { 1217, PT_PC, ucp_Pd },
- { 1220, PT_PC, ucp_Pe },
- { 1223, PT_PC, ucp_Pf },
- { 1226, PT_SC, ucp_Phags_Pa },
- { 1235, PT_SC, ucp_Phoenician },
- { 1246, PT_PC, ucp_Pi },
- { 1249, PT_PC, ucp_Po },
- { 1252, PT_PC, ucp_Ps },
- { 1255, PT_SC, ucp_Psalter_Pahlavi },
- { 1271, PT_SC, ucp_Rejang },
- { 1278, PT_SC, ucp_Runic },
- { 1284, PT_GC, ucp_S },
- { 1286, PT_SC, ucp_Samaritan },
- { 1296, PT_SC, ucp_Saurashtra },
- { 1307, PT_PC, ucp_Sc },
- { 1310, PT_SC, ucp_Sharada },
- { 1318, PT_SC, ucp_Shavian },
- { 1326, PT_SC, ucp_Siddham },
- { 1334, PT_SC, ucp_SignWriting },
- { 1346, PT_SC, ucp_Sinhala },
- { 1354, PT_PC, ucp_Sk },
- { 1357, PT_PC, ucp_Sm },
- { 1360, PT_PC, ucp_So },
- { 1363, PT_SC, ucp_Sogdian },
- { 1371, PT_SC, ucp_Sora_Sompeng },
- { 1384, PT_SC, ucp_Soyombo },
- { 1392, PT_SC, ucp_Sundanese },
- { 1402, PT_SC, ucp_Syloti_Nagri },
- { 1415, PT_SC, ucp_Syriac },
- { 1422, PT_SC, ucp_Tagalog },
- { 1430, PT_SC, ucp_Tagbanwa },
- { 1439, PT_SC, ucp_Tai_Le },
- { 1446, PT_SC, ucp_Tai_Tham },
- { 1455, PT_SC, ucp_Tai_Viet },
- { 1464, PT_SC, ucp_Takri },
- { 1470, PT_SC, ucp_Tamil },
- { 1476, PT_SC, ucp_Tangut },
- { 1483, PT_SC, ucp_Telugu },
- { 1490, PT_SC, ucp_Thaana },
- { 1497, PT_SC, ucp_Thai },
- { 1502, PT_SC, ucp_Tibetan },
- { 1510, PT_SC, ucp_Tifinagh },
- { 1519, PT_SC, ucp_Tirhuta },
- { 1527, PT_SC, ucp_Ugaritic },
- { 1536, PT_SC, ucp_Unknown },
- { 1544, PT_SC, ucp_Vai },
- { 1548, PT_SC, ucp_Wancho },
- { 1555, PT_SC, ucp_Warang_Citi },
- { 1567, PT_ALNUM, 0 },
- { 1571, PT_PXSPACE, 0 },
- { 1575, PT_SPACE, 0 },
- { 1579, PT_UCNC, 0 },
- { 1583, PT_WORD, 0 },
- { 1587, PT_SC, ucp_Yezidi },
- { 1594, PT_SC, ucp_Yi },
- { 1597, PT_GC, ucp_Z },
- { 1599, PT_SC, ucp_Zanabazar_Square },
- { 1616, PT_PC, ucp_Zl },
- { 1619, PT_PC, ucp_Zp },
- { 1622, PT_PC, ucp_Zs }
+ { 276, PT_SC, ucp_Cypro_Minoan },
+ { 289, PT_SC, ucp_Cyrillic },
+ { 298, PT_SC, ucp_Deseret },
+ { 306, PT_SC, ucp_Devanagari },
+ { 317, PT_SC, ucp_Dives_Akuru },
+ { 329, PT_SC, ucp_Dogra },
+ { 335, PT_SC, ucp_Duployan },
+ { 344, PT_SC, ucp_Egyptian_Hieroglyphs },
+ { 365, PT_SC, ucp_Elbasan },
+ { 373, PT_SC, ucp_Elymaic },
+ { 381, PT_SC, ucp_Ethiopic },
+ { 390, PT_SC, ucp_Georgian },
+ { 399, PT_SC, ucp_Glagolitic },
+ { 410, PT_SC, ucp_Gothic },
+ { 417, PT_SC, ucp_Grantha },
+ { 425, PT_SC, ucp_Greek },
+ { 431, PT_SC, ucp_Gujarati },
+ { 440, PT_SC, ucp_Gunjala_Gondi },
+ { 454, PT_SC, ucp_Gurmukhi },
+ { 463, PT_SC, ucp_Han },
+ { 467, PT_SC, ucp_Hangul },
+ { 474, PT_SC, ucp_Hanifi_Rohingya },
+ { 490, PT_SC, ucp_Hanunoo },
+ { 498, PT_SC, ucp_Hatran },
+ { 505, PT_SC, ucp_Hebrew },
+ { 512, PT_SC, ucp_Hiragana },
+ { 521, PT_SC, ucp_Imperial_Aramaic },
+ { 538, PT_SC, ucp_Inherited },
+ { 548, PT_SC, ucp_Inscriptional_Pahlavi },
+ { 570, PT_SC, ucp_Inscriptional_Parthian },
+ { 593, PT_SC, ucp_Javanese },
+ { 602, PT_SC, ucp_Kaithi },
+ { 609, PT_SC, ucp_Kannada },
+ { 617, PT_SC, ucp_Katakana },
+ { 626, PT_SC, ucp_Kayah_Li },
+ { 635, PT_SC, ucp_Kharoshthi },
+ { 646, PT_SC, ucp_Khitan_Small_Script },
+ { 666, PT_SC, ucp_Khmer },
+ { 672, PT_SC, ucp_Khojki },
+ { 679, PT_SC, ucp_Khudawadi },
+ { 689, PT_GC, ucp_L },
+ { 691, PT_LAMP, 0 },
+ { 694, PT_SC, ucp_Lao },
+ { 698, PT_SC, ucp_Latin },
+ { 704, PT_SC, ucp_Lepcha },
+ { 711, PT_SC, ucp_Limbu },
+ { 717, PT_SC, ucp_Linear_A },
+ { 726, PT_SC, ucp_Linear_B },
+ { 735, PT_SC, ucp_Lisu },
+ { 740, PT_PC, ucp_Ll },
+ { 743, PT_PC, ucp_Lm },
+ { 746, PT_PC, ucp_Lo },
+ { 749, PT_PC, ucp_Lt },
+ { 752, PT_PC, ucp_Lu },
+ { 755, PT_SC, ucp_Lycian },
+ { 762, PT_SC, ucp_Lydian },
+ { 769, PT_GC, ucp_M },
+ { 771, PT_SC, ucp_Mahajani },
+ { 780, PT_SC, ucp_Makasar },
+ { 788, PT_SC, ucp_Malayalam },
+ { 798, PT_SC, ucp_Mandaic },
+ { 806, PT_SC, ucp_Manichaean },
+ { 817, PT_SC, ucp_Marchen },
+ { 825, PT_SC, ucp_Masaram_Gondi },
+ { 839, PT_PC, ucp_Mc },
+ { 842, PT_PC, ucp_Me },
+ { 845, PT_SC, ucp_Medefaidrin },
+ { 857, PT_SC, ucp_Meetei_Mayek },
+ { 870, PT_SC, ucp_Mende_Kikakui },
+ { 884, PT_SC, ucp_Meroitic_Cursive },
+ { 901, PT_SC, ucp_Meroitic_Hieroglyphs },
+ { 922, PT_SC, ucp_Miao },
+ { 927, PT_PC, ucp_Mn },
+ { 930, PT_SC, ucp_Modi },
+ { 935, PT_SC, ucp_Mongolian },
+ { 945, PT_SC, ucp_Mro },
+ { 949, PT_SC, ucp_Multani },
+ { 957, PT_SC, ucp_Myanmar },
+ { 965, PT_GC, ucp_N },
+ { 967, PT_SC, ucp_Nabataean },
+ { 977, PT_SC, ucp_Nandinagari },
+ { 989, PT_PC, ucp_Nd },
+ { 992, PT_SC, ucp_New_Tai_Lue },
+ { 1004, PT_SC, ucp_Newa },
+ { 1009, PT_SC, ucp_Nko },
+ { 1013, PT_PC, ucp_Nl },
+ { 1016, PT_PC, ucp_No },
+ { 1019, PT_SC, ucp_Nushu },
+ { 1025, PT_SC, ucp_Nyiakeng_Puachue_Hmong },
+ { 1048, PT_SC, ucp_Ogham },
+ { 1054, PT_SC, ucp_Ol_Chiki },
+ { 1063, PT_SC, ucp_Old_Hungarian },
+ { 1077, PT_SC, ucp_Old_Italic },
+ { 1088, PT_SC, ucp_Old_North_Arabian },
+ { 1106, PT_SC, ucp_Old_Permic },
+ { 1117, PT_SC, ucp_Old_Persian },
+ { 1129, PT_SC, ucp_Old_Sogdian },
+ { 1141, PT_SC, ucp_Old_South_Arabian },
+ { 1159, PT_SC, ucp_Old_Turkic },
+ { 1170, PT_SC, ucp_Old_Uyghur },
+ { 1181, PT_SC, ucp_Oriya },
+ { 1187, PT_SC, ucp_Osage },
+ { 1193, PT_SC, ucp_Osmanya },
+ { 1201, PT_GC, ucp_P },
+ { 1203, PT_SC, ucp_Pahawh_Hmong },
+ { 1216, PT_SC, ucp_Palmyrene },
+ { 1226, PT_SC, ucp_Pau_Cin_Hau },
+ { 1238, PT_PC, ucp_Pc },
+ { 1241, PT_PC, ucp_Pd },
+ { 1244, PT_PC, ucp_Pe },
+ { 1247, PT_PC, ucp_Pf },
+ { 1250, PT_SC, ucp_Phags_Pa },
+ { 1259, PT_SC, ucp_Phoenician },
+ { 1270, PT_PC, ucp_Pi },
+ { 1273, PT_PC, ucp_Po },
+ { 1276, PT_PC, ucp_Ps },
+ { 1279, PT_SC, ucp_Psalter_Pahlavi },
+ { 1295, PT_SC, ucp_Rejang },
+ { 1302, PT_SC, ucp_Runic },
+ { 1308, PT_GC, ucp_S },
+ { 1310, PT_SC, ucp_Samaritan },
+ { 1320, PT_SC, ucp_Saurashtra },
+ { 1331, PT_PC, ucp_Sc },
+ { 1334, PT_SC, ucp_Sharada },
+ { 1342, PT_SC, ucp_Shavian },
+ { 1350, PT_SC, ucp_Siddham },
+ { 1358, PT_SC, ucp_SignWriting },
+ { 1370, PT_SC, ucp_Sinhala },
+ { 1378, PT_PC, ucp_Sk },
+ { 1381, PT_PC, ucp_Sm },
+ { 1384, PT_PC, ucp_So },
+ { 1387, PT_SC, ucp_Sogdian },
+ { 1395, PT_SC, ucp_Sora_Sompeng },
+ { 1408, PT_SC, ucp_Soyombo },
+ { 1416, PT_SC, ucp_Sundanese },
+ { 1426, PT_SC, ucp_Syloti_Nagri },
+ { 1439, PT_SC, ucp_Syriac },
+ { 1446, PT_SC, ucp_Tagalog },
+ { 1454, PT_SC, ucp_Tagbanwa },
+ { 1463, PT_SC, ucp_Tai_Le },
+ { 1470, PT_SC, ucp_Tai_Tham },
+ { 1479, PT_SC, ucp_Tai_Viet },
+ { 1488, PT_SC, ucp_Takri },
+ { 1494, PT_SC, ucp_Tamil },
+ { 1500, PT_SC, ucp_Tangsa },
+ { 1507, PT_SC, ucp_Tangut },
+ { 1514, PT_SC, ucp_Telugu },
+ { 1521, PT_SC, ucp_Thaana },
+ { 1528, PT_SC, ucp_Thai },
+ { 1533, PT_SC, ucp_Tibetan },
+ { 1541, PT_SC, ucp_Tifinagh },
+ { 1550, PT_SC, ucp_Tirhuta },
+ { 1558, PT_SC, ucp_Toto },
+ { 1563, PT_SC, ucp_Ugaritic },
+ { 1572, PT_SC, ucp_Unknown },
+ { 1580, PT_SC, ucp_Vai },
+ { 1584, PT_SC, ucp_Vithkuqi },
+ { 1593, PT_SC, ucp_Wancho },
+ { 1600, PT_SC, ucp_Warang_Citi },
+ { 1612, PT_ALNUM, 0 },
+ { 1616, PT_PXSPACE, 0 },
+ { 1620, PT_SPACE, 0 },
+ { 1624, PT_UCNC, 0 },
+ { 1628, PT_WORD, 0 },
+ { 1632, PT_SC, ucp_Yezidi },
+ { 1639, PT_SC, ucp_Yi },
+ { 1642, PT_GC, ucp_Z },
+ { 1644, PT_SC, ucp_Zanabazar_Square },
+ { 1661, PT_PC, ucp_Zl },
+ { 1664, PT_PC, ucp_Zp },
+ { 1667, PT_PC, ucp_Zs }
};
const size_t PRIV(utt_size) = sizeof(PRIV(utt)) / sizeof(ucp_type_table);
diff --git a/thirdparty/pcre2/src/pcre2_ucd.c b/thirdparty/pcre2/src/pcre2_ucd.c
index 46e23ff06b..0b8ac75bd4 100644
--- a/thirdparty/pcre2/src/pcre2_ucd.c
+++ b/thirdparty/pcre2/src/pcre2_ucd.c
@@ -20,7 +20,7 @@ needed. */
/* Unicode character database. */
/* This file was autogenerated by the MultiStage2.py script. */
-/* Total size: 101044 bytes, block size: 128. */
+/* Total size: 102844 bytes, block size: 128. */
/* The tables herein are needed only when UCP support is built,
and in PCRE2 that happens automatically with UTF support.
@@ -39,7 +39,7 @@ const uint16_t PRIV(ucd_stage2)[] = {0};
const uint32_t PRIV(ucd_caseless_sets)[] = {0};
#else
-const char *PRIV(unicode_version) = "13.0.0";
+const char *PRIV(unicode_version) = "14.0.0";
/* If the 32-bit library is run in non-32-bit mode, character values
greater than 0x10ffff may be encountered. For these we set up a
@@ -116,16 +116,16 @@ set of 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)[] = {
- 65, /* Number of subsequent values */
+ 66, /* 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, 0x16b59,
- 0x1d7d7, 0x1d7e1, 0x1d7eb, 0x1d7f5, 0x1d7ff, 0x1e149, 0x1e2f9, 0x1e959,
- 0x1fbf9,
+ 0x11739, 0x118e9, 0x11959, 0x11c59, 0x11d59, 0x11da9, 0x16a69, 0x16ac9,
+ 0x16b59, 0x1d7d7, 0x1d7e1, 0x1d7eb, 0x1d7f5, 0x1d7ff, 0x1e149, 0x1e2f9,
+ 0x1e959, 0x1fbf9,
};
/* This vector is a list of lists of scripts for the Script Extension
@@ -135,55 +135,59 @@ const uint8_t PRIV(ucd_script_sets)[] = {
/* 0 */ 0,
/* 1 */ 1, 11, 0,
/* 4 */ 1, 144, 0,
- /* 7 */ 1, 50, 0,
- /* 10 */ 1, 56, 0,
- /* 13 */ 3, 15, 0,
- /* 16 */ 4, 23, 0,
- /* 19 */ 6, 84, 0,
- /* 22 */ 12, 36, 0,
- /* 25 */ 13, 18, 0,
- /* 28 */ 13, 34, 0,
- /* 31 */ 13, 118, 0,
- /* 34 */ 13, 50, 0,
- /* 37 */ 15, 107, 0,
- /* 40 */ 15, 150, 0,
- /* 43 */ 15, 100, 0,
- /* 46 */ 15, 54, 0,
- /* 49 */ 17, 34, 0,
- /* 52 */ 107, 54, 0,
- /* 55 */ 21, 108, 0,
- /* 58 */ 22, 129, 0,
- /* 61 */ 23, 34, 0,
- /* 64 */ 27, 30, 0,
- /* 67 */ 29, 150, 0,
- /* 70 */ 34, 38, 0,
- /* 73 */ 38, 65, 0,
- /* 76 */ 1, 50, 56, 0,
- /* 80 */ 1, 56, 156, 0,
- /* 84 */ 3, 96, 49, 0,
- /* 88 */ 96, 39, 53, 0,
- /* 92 */ 12, 110, 36, 0,
- /* 96 */ 15, 107, 29, 0,
- /* 100 */ 15, 107, 34, 0,
- /* 104 */ 23, 27, 30, 0,
- /* 108 */ 69, 34, 39, 0,
- /* 112 */ 3, 15, 107, 29, 0,
- /* 117 */ 7, 25, 52, 51, 0,
- /* 122 */ 15, 142, 85, 111, 0,
- /* 127 */ 1, 144, 50, 56, 156, 0,
- /* 133 */ 4, 24, 23, 27, 30, 0,
- /* 139 */ 4, 24, 23, 27, 30, 61, 0,
- /* 146 */ 15, 29, 37, 44, 54, 55, 0,
- /* 153 */ 132, 1, 95, 112, 121, 144, 148, 50, 0,
- /* 162 */ 3, 15, 107, 29, 150, 44, 55, 124, 0,
- /* 171 */ 15, 142, 21, 22, 108, 85, 111, 114, 109, 102, 124, 0,
- /* 183 */ 3, 15, 107, 21, 22, 29, 34, 37, 44, 54, 55, 124, 0,
- /* 196 */ 3, 15, 107, 21, 22, 29, 34, 37, 44, 100, 54, 55, 124, 0,
- /* 210 */ 15, 142, 21, 22, 108, 29, 85, 111, 114, 150, 109, 102, 124, 0,
- /* 224 */ 15, 142, 21, 22, 108, 29, 85, 111, 37, 114, 150, 109, 102, 124, 0,
- /* 239 */ 3, 15, 142, 143, 138, 107, 21, 22, 29, 111, 37, 150, 44, 109, 48, 49, 102, 54, 55, 124, 0,
- /* 260 */ 3, 15, 142, 143, 138, 107, 21, 22, 29, 35, 111, 37, 150, 44, 109, 48, 49, 102, 54, 55, 124, 0,
- /* 282 */
+ /* 7 */ 1, 64, 0,
+ /* 10 */ 1, 50, 0,
+ /* 13 */ 1, 56, 0,
+ /* 16 */ 3, 15, 0,
+ /* 19 */ 4, 23, 0,
+ /* 22 */ 6, 84, 0,
+ /* 25 */ 12, 36, 0,
+ /* 28 */ 13, 18, 0,
+ /* 31 */ 13, 34, 0,
+ /* 34 */ 13, 118, 0,
+ /* 37 */ 13, 50, 0,
+ /* 40 */ 15, 107, 0,
+ /* 43 */ 15, 150, 0,
+ /* 46 */ 15, 100, 0,
+ /* 49 */ 15, 54, 0,
+ /* 52 */ 17, 34, 0,
+ /* 55 */ 107, 54, 0,
+ /* 58 */ 21, 108, 0,
+ /* 61 */ 22, 129, 0,
+ /* 64 */ 23, 34, 0,
+ /* 67 */ 27, 30, 0,
+ /* 70 */ 29, 150, 0,
+ /* 73 */ 34, 38, 0,
+ /* 76 */ 112, 158, 0,
+ /* 79 */ 38, 65, 0,
+ /* 82 */ 1, 50, 56, 0,
+ /* 86 */ 1, 56, 156, 0,
+ /* 90 */ 3, 96, 49, 0,
+ /* 94 */ 96, 39, 53, 0,
+ /* 98 */ 157, 12, 36, 0,
+ /* 102 */ 12, 110, 36, 0,
+ /* 106 */ 15, 107, 29, 0,
+ /* 110 */ 15, 107, 34, 0,
+ /* 114 */ 23, 27, 30, 0,
+ /* 118 */ 69, 34, 39, 0,
+ /* 122 */ 3, 15, 107, 29, 0,
+ /* 127 */ 7, 25, 52, 51, 0,
+ /* 132 */ 15, 142, 85, 111, 0,
+ /* 137 */ 4, 24, 23, 27, 30, 0,
+ /* 143 */ 1, 64, 144, 50, 56, 156, 0,
+ /* 150 */ 4, 24, 23, 27, 30, 61, 0,
+ /* 157 */ 15, 29, 37, 44, 54, 55, 0,
+ /* 164 */ 132, 1, 64, 144, 50, 56, 156, 0,
+ /* 172 */ 3, 15, 107, 29, 150, 44, 55, 124, 0,
+ /* 181 */ 132, 1, 95, 112, 158, 121, 144, 148, 50, 0,
+ /* 191 */ 15, 142, 21, 22, 108, 85, 111, 114, 109, 102, 124, 0,
+ /* 203 */ 3, 15, 107, 21, 22, 29, 34, 37, 44, 54, 55, 124, 0,
+ /* 216 */ 3, 15, 107, 21, 22, 29, 34, 37, 44, 100, 54, 55, 124, 0,
+ /* 230 */ 15, 142, 21, 22, 108, 29, 85, 111, 114, 150, 109, 102, 124, 0,
+ /* 244 */ 15, 142, 21, 22, 108, 29, 85, 111, 37, 114, 150, 109, 102, 124, 0,
+ /* 259 */ 3, 15, 142, 143, 138, 107, 21, 22, 29, 111, 37, 150, 44, 109, 48, 49, 102, 54, 55, 124, 0,
+ /* 280 */ 3, 15, 142, 143, 138, 107, 21, 22, 29, 35, 111, 37, 150, 44, 109, 48, 49, 102, 54, 55, 124, 0,
+ /* 302 */
};
/* These are the main two-stage UCD tables. The fields in each record are:
@@ -192,7 +196,7 @@ offset to multichar other cases or zero (8 bits), offset to other case
or zero (32 bits, signed), script extension (16 bits, signed), and a dummy
16-bit field to make the whole thing a multiple of 4 bytes. */
-const ucd_record PRIV(ucd_records)[] = { /* 11700 bytes, record size 12 */
+const ucd_record PRIV(ucd_records)[] = { /* 11964 bytes, record size 12 */
{ 10, 0, 2, 0, 0, 10, 256, }, /* 0 */
{ 10, 0, 2, 0, 0, 10, 0, }, /* 1 */
{ 10, 0, 1, 0, 0, 10, 0, }, /* 2 */
@@ -390,9 +394,9 @@ const ucd_record PRIV(ucd_records)[] = { /* 11700 bytes, record size 12 */
{ 13, 9, 12, 88, 1, 13, 0, }, /* 194 */
{ 13, 5, 12, 88, -1, 13, 0, }, /* 195 */
{ 13, 26, 12, 0, 0, 13, 0, }, /* 196 */
- { 13, 12, 3, 0, 0, -31, 0, }, /* 197 */
- { 13, 12, 3, 0, 0, -25, 0, }, /* 198 */
- { 28, 12, 3, 0, 0, -28, 0, }, /* 199 */
+ { 13, 12, 3, 0, 0, -34, 0, }, /* 197 */
+ { 13, 12, 3, 0, 0, -28, 0, }, /* 198 */
+ { 28, 12, 3, 0, 0, -31, 0, }, /* 199 */
{ 13, 11, 3, 0, 0, 13, 0, }, /* 200 */
{ 13, 9, 12, 0, 15, 13, 0, }, /* 201 */
{ 13, 5, 12, 0, -15, 13, 0, }, /* 202 */
@@ -413,761 +417,783 @@ const ucd_record PRIV(ucd_records)[] = { /* 11700 bytes, record size 12 */
{ 1, 25, 12, 0, 0, 1, 0, }, /* 217 */
{ 1, 21, 12, 0, 0, 1, 0, }, /* 218 */
{ 1, 23, 12, 0, 0, 1, 0, }, /* 219 */
- { 10, 21, 12, 0, 0, -127, 0, }, /* 220 */
+ { 10, 21, 12, 0, 0, -143, 0, }, /* 220 */
{ 1, 26, 12, 0, 0, 1, 0, }, /* 221 */
{ 1, 12, 3, 0, 0, 1, 0, }, /* 222 */
- { 1, 1, 2, 0, 0, -76, 0, }, /* 223 */
- { 1, 7, 12, 0, 0, 1, 0, }, /* 224 */
- { 10, 6, 12, 0, 0, -153, 0, }, /* 225 */
- { 28, 12, 3, 0, 0, -7, 0, }, /* 226 */
- { 1, 13, 12, 0, 0, -80, 0, }, /* 227 */
- { 1, 21, 12, 0, 0, -4, 0, }, /* 228 */
- { 1, 6, 12, 0, 0, 1, 0, }, /* 229 */
- { 1, 13, 12, 0, 0, 1, 0, }, /* 230 */
- { 50, 21, 12, 0, 0, 50, 0, }, /* 231 */
- { 50, 1, 4, 0, 0, 50, 0, }, /* 232 */
- { 50, 7, 12, 0, 0, 50, 0, }, /* 233 */
- { 50, 12, 3, 0, 0, 50, 0, }, /* 234 */
- { 56, 7, 12, 0, 0, 56, 0, }, /* 235 */
- { 56, 12, 3, 0, 0, 56, 0, }, /* 236 */
- { 64, 13, 12, 0, 0, 64, 0, }, /* 237 */
- { 64, 7, 12, 0, 0, 64, 0, }, /* 238 */
- { 64, 12, 3, 0, 0, 64, 0, }, /* 239 */
- { 64, 6, 12, 0, 0, 64, 0, }, /* 240 */
- { 64, 26, 12, 0, 0, 64, 0, }, /* 241 */
- { 64, 21, 12, 0, 0, 64, 0, }, /* 242 */
- { 64, 23, 12, 0, 0, 64, 0, }, /* 243 */
- { 90, 7, 12, 0, 0, 90, 0, }, /* 244 */
- { 90, 12, 3, 0, 0, 90, 0, }, /* 245 */
- { 90, 6, 12, 0, 0, 90, 0, }, /* 246 */
- { 90, 21, 12, 0, 0, 90, 0, }, /* 247 */
- { 95, 7, 12, 0, 0, 95, 0, }, /* 248 */
- { 95, 12, 3, 0, 0, 95, 0, }, /* 249 */
- { 95, 21, 12, 0, 0, 95, 0, }, /* 250 */
- { 15, 12, 3, 0, 0, 15, 0, }, /* 251 */
- { 15, 10, 5, 0, 0, 15, 0, }, /* 252 */
- { 15, 7, 12, 0, 0, 15, 0, }, /* 253 */
- { 28, 12, 3, 0, 0, -196, 0, }, /* 254 */
- { 28, 12, 3, 0, 0, -183, 0, }, /* 255 */
- { 10, 21, 12, 0, 0, -239, 0, }, /* 256 */
- { 10, 21, 12, 0, 0, -260, 0, }, /* 257 */
- { 15, 13, 12, 0, 0, -122, 0, }, /* 258 */
- { 15, 21, 12, 0, 0, 15, 0, }, /* 259 */
- { 15, 6, 12, 0, 0, 15, 0, }, /* 260 */
- { 3, 7, 12, 0, 0, 3, 0, }, /* 261 */
- { 3, 12, 3, 0, 0, 3, 0, }, /* 262 */
- { 3, 10, 5, 0, 0, 3, 0, }, /* 263 */
- { 3, 10, 3, 0, 0, 3, 0, }, /* 264 */
- { 3, 13, 12, 0, 0, -84, 0, }, /* 265 */
- { 3, 23, 12, 0, 0, 3, 0, }, /* 266 */
- { 3, 15, 12, 0, 0, 3, 0, }, /* 267 */
- { 3, 26, 12, 0, 0, 3, 0, }, /* 268 */
- { 3, 21, 12, 0, 0, 3, 0, }, /* 269 */
- { 22, 12, 3, 0, 0, 22, 0, }, /* 270 */
- { 22, 10, 5, 0, 0, 22, 0, }, /* 271 */
- { 22, 7, 12, 0, 0, 22, 0, }, /* 272 */
- { 22, 13, 12, 0, 0, -58, 0, }, /* 273 */
- { 22, 21, 12, 0, 0, 22, 0, }, /* 274 */
- { 21, 12, 3, 0, 0, 21, 0, }, /* 275 */
- { 21, 10, 5, 0, 0, 21, 0, }, /* 276 */
- { 21, 7, 12, 0, 0, 21, 0, }, /* 277 */
- { 21, 13, 12, 0, 0, -55, 0, }, /* 278 */
- { 21, 21, 12, 0, 0, 21, 0, }, /* 279 */
- { 21, 23, 12, 0, 0, 21, 0, }, /* 280 */
- { 44, 12, 3, 0, 0, 44, 0, }, /* 281 */
- { 44, 10, 5, 0, 0, 44, 0, }, /* 282 */
- { 44, 7, 12, 0, 0, 44, 0, }, /* 283 */
- { 44, 10, 3, 0, 0, 44, 0, }, /* 284 */
- { 44, 13, 12, 0, 0, 44, 0, }, /* 285 */
- { 44, 26, 12, 0, 0, 44, 0, }, /* 286 */
- { 44, 15, 12, 0, 0, 44, 0, }, /* 287 */
- { 54, 12, 3, 0, 0, 54, 0, }, /* 288 */
- { 54, 7, 12, 0, 0, 54, 0, }, /* 289 */
- { 54, 10, 3, 0, 0, 54, 0, }, /* 290 */
- { 54, 10, 5, 0, 0, 54, 0, }, /* 291 */
- { 54, 13, 12, 0, 0, -52, 0, }, /* 292 */
- { 54, 15, 12, 0, 0, -52, 0, }, /* 293 */
- { 54, 26, 12, 0, 0, -52, 0, }, /* 294 */
- { 54, 26, 12, 0, 0, 54, 0, }, /* 295 */
- { 54, 23, 12, 0, 0, 54, 0, }, /* 296 */
- { 55, 12, 3, 0, 0, 55, 0, }, /* 297 */
- { 55, 10, 5, 0, 0, 55, 0, }, /* 298 */
- { 55, 7, 12, 0, 0, 55, 0, }, /* 299 */
- { 55, 13, 12, 0, 0, 55, 0, }, /* 300 */
- { 55, 21, 12, 0, 0, 55, 0, }, /* 301 */
- { 55, 15, 12, 0, 0, 55, 0, }, /* 302 */
- { 55, 26, 12, 0, 0, 55, 0, }, /* 303 */
- { 29, 7, 12, 0, 0, 29, 0, }, /* 304 */
- { 29, 12, 3, 0, 0, 29, 0, }, /* 305 */
- { 29, 10, 5, 0, 0, 29, 0, }, /* 306 */
- { 29, 21, 12, 0, 0, 29, 0, }, /* 307 */
- { 29, 10, 3, 0, 0, 29, 0, }, /* 308 */
- { 29, 13, 12, 0, 0, -67, 0, }, /* 309 */
- { 37, 12, 3, 0, 0, 37, 0, }, /* 310 */
- { 37, 10, 5, 0, 0, 37, 0, }, /* 311 */
- { 37, 7, 12, 0, 0, 37, 0, }, /* 312 */
- { 37, 10, 3, 0, 0, 37, 0, }, /* 313 */
- { 37, 7, 4, 0, 0, 37, 0, }, /* 314 */
- { 37, 26, 12, 0, 0, 37, 0, }, /* 315 */
- { 37, 15, 12, 0, 0, 37, 0, }, /* 316 */
- { 37, 13, 12, 0, 0, 37, 0, }, /* 317 */
- { 48, 12, 3, 0, 0, 48, 0, }, /* 318 */
- { 48, 10, 5, 0, 0, 48, 0, }, /* 319 */
- { 48, 7, 12, 0, 0, 48, 0, }, /* 320 */
- { 48, 10, 3, 0, 0, 48, 0, }, /* 321 */
- { 48, 13, 12, 0, 0, 48, 0, }, /* 322 */
- { 48, 21, 12, 0, 0, 48, 0, }, /* 323 */
- { 57, 7, 12, 0, 0, 57, 0, }, /* 324 */
- { 57, 12, 3, 0, 0, 57, 0, }, /* 325 */
- { 57, 7, 5, 0, 0, 57, 0, }, /* 326 */
- { 57, 6, 12, 0, 0, 57, 0, }, /* 327 */
- { 57, 21, 12, 0, 0, 57, 0, }, /* 328 */
- { 57, 13, 12, 0, 0, 57, 0, }, /* 329 */
- { 33, 7, 12, 0, 0, 33, 0, }, /* 330 */
- { 33, 12, 3, 0, 0, 33, 0, }, /* 331 */
- { 33, 7, 5, 0, 0, 33, 0, }, /* 332 */
- { 33, 6, 12, 0, 0, 33, 0, }, /* 333 */
- { 33, 13, 12, 0, 0, 33, 0, }, /* 334 */
- { 58, 7, 12, 0, 0, 58, 0, }, /* 335 */
- { 58, 26, 12, 0, 0, 58, 0, }, /* 336 */
- { 58, 21, 12, 0, 0, 58, 0, }, /* 337 */
- { 58, 12, 3, 0, 0, 58, 0, }, /* 338 */
- { 58, 13, 12, 0, 0, 58, 0, }, /* 339 */
- { 58, 15, 12, 0, 0, 58, 0, }, /* 340 */
- { 58, 22, 12, 0, 0, 58, 0, }, /* 341 */
- { 58, 18, 12, 0, 0, 58, 0, }, /* 342 */
- { 58, 10, 5, 0, 0, 58, 0, }, /* 343 */
- { 39, 7, 12, 0, 0, 39, 0, }, /* 344 */
- { 39, 10, 12, 0, 0, 39, 0, }, /* 345 */
- { 39, 12, 3, 0, 0, 39, 0, }, /* 346 */
- { 39, 10, 5, 0, 0, 39, 0, }, /* 347 */
- { 39, 13, 12, 0, 0, -88, 0, }, /* 348 */
- { 39, 21, 12, 0, 0, 39, 0, }, /* 349 */
- { 39, 13, 12, 0, 0, 39, 0, }, /* 350 */
- { 39, 26, 12, 0, 0, 39, 0, }, /* 351 */
- { 17, 9, 12, 0, 7264, 17, 0, }, /* 352 */
- { 17, 5, 12, 0, 3008, 17, 0, }, /* 353 */
- { 10, 21, 12, 0, 0, -49, 0, }, /* 354 */
- { 17, 6, 12, 0, 0, 17, 0, }, /* 355 */
- { 24, 7, 6, 0, 0, 24, 0, }, /* 356 */
- { 24, 7, 7, 0, 0, 24, 0, }, /* 357 */
- { 24, 7, 8, 0, 0, 24, 0, }, /* 358 */
- { 16, 7, 12, 0, 0, 16, 0, }, /* 359 */
- { 16, 12, 3, 0, 0, 16, 0, }, /* 360 */
- { 16, 21, 12, 0, 0, 16, 0, }, /* 361 */
- { 16, 15, 12, 0, 0, 16, 0, }, /* 362 */
- { 16, 26, 12, 0, 0, 16, 0, }, /* 363 */
- { 9, 9, 12, 0, 38864, 9, 0, }, /* 364 */
- { 9, 9, 12, 0, 8, 9, 0, }, /* 365 */
- { 9, 5, 12, 0, -8, 9, 0, }, /* 366 */
- { 8, 17, 12, 0, 0, 8, 0, }, /* 367 */
- { 8, 7, 12, 0, 0, 8, 0, }, /* 368 */
- { 8, 26, 12, 0, 0, 8, 0, }, /* 369 */
- { 8, 21, 12, 0, 0, 8, 0, }, /* 370 */
- { 41, 29, 12, 0, 0, 41, 0, }, /* 371 */
- { 41, 7, 12, 0, 0, 41, 0, }, /* 372 */
- { 41, 22, 12, 0, 0, 41, 0, }, /* 373 */
- { 41, 18, 12, 0, 0, 41, 0, }, /* 374 */
- { 46, 7, 12, 0, 0, 46, 0, }, /* 375 */
- { 46, 14, 12, 0, 0, 46, 0, }, /* 376 */
- { 51, 7, 12, 0, 0, 51, 0, }, /* 377 */
- { 51, 12, 3, 0, 0, 51, 0, }, /* 378 */
- { 25, 7, 12, 0, 0, 25, 0, }, /* 379 */
- { 25, 12, 3, 0, 0, 25, 0, }, /* 380 */
- { 10, 21, 12, 0, 0, -117, 0, }, /* 381 */
- { 7, 7, 12, 0, 0, 7, 0, }, /* 382 */
- { 7, 12, 3, 0, 0, 7, 0, }, /* 383 */
- { 52, 7, 12, 0, 0, 52, 0, }, /* 384 */
- { 52, 12, 3, 0, 0, 52, 0, }, /* 385 */
- { 32, 7, 12, 0, 0, 32, 0, }, /* 386 */
- { 32, 12, 3, 0, 0, 32, 0, }, /* 387 */
- { 32, 10, 5, 0, 0, 32, 0, }, /* 388 */
- { 32, 21, 12, 0, 0, 32, 0, }, /* 389 */
- { 32, 6, 12, 0, 0, 32, 0, }, /* 390 */
- { 32, 23, 12, 0, 0, 32, 0, }, /* 391 */
- { 32, 13, 12, 0, 0, 32, 0, }, /* 392 */
- { 32, 15, 12, 0, 0, 32, 0, }, /* 393 */
- { 38, 21, 12, 0, 0, 38, 0, }, /* 394 */
- { 10, 21, 12, 0, 0, -73, 0, }, /* 395 */
- { 38, 17, 12, 0, 0, 38, 0, }, /* 396 */
- { 38, 12, 3, 0, 0, 38, 0, }, /* 397 */
- { 38, 1, 2, 0, 0, 38, 0, }, /* 398 */
- { 38, 13, 12, 0, 0, 38, 0, }, /* 399 */
- { 38, 7, 12, 0, 0, 38, 0, }, /* 400 */
- { 38, 6, 12, 0, 0, 38, 0, }, /* 401 */
- { 35, 7, 12, 0, 0, 35, 0, }, /* 402 */
- { 35, 12, 3, 0, 0, 35, 0, }, /* 403 */
- { 35, 10, 5, 0, 0, 35, 0, }, /* 404 */
- { 35, 26, 12, 0, 0, 35, 0, }, /* 405 */
- { 35, 21, 12, 0, 0, 35, 0, }, /* 406 */
- { 35, 13, 12, 0, 0, 35, 0, }, /* 407 */
- { 53, 7, 12, 0, 0, 53, 0, }, /* 408 */
- { 40, 7, 12, 0, 0, 40, 0, }, /* 409 */
- { 40, 13, 12, 0, 0, 40, 0, }, /* 410 */
- { 40, 15, 12, 0, 0, 40, 0, }, /* 411 */
- { 40, 26, 12, 0, 0, 40, 0, }, /* 412 */
- { 32, 26, 12, 0, 0, 32, 0, }, /* 413 */
- { 6, 7, 12, 0, 0, 6, 0, }, /* 414 */
- { 6, 12, 3, 0, 0, 6, 0, }, /* 415 */
- { 6, 10, 5, 0, 0, 6, 0, }, /* 416 */
- { 6, 21, 12, 0, 0, 6, 0, }, /* 417 */
- { 91, 7, 12, 0, 0, 91, 0, }, /* 418 */
- { 91, 10, 5, 0, 0, 91, 0, }, /* 419 */
- { 91, 12, 3, 0, 0, 91, 0, }, /* 420 */
- { 91, 10, 12, 0, 0, 91, 0, }, /* 421 */
- { 91, 13, 12, 0, 0, 91, 0, }, /* 422 */
- { 91, 21, 12, 0, 0, 91, 0, }, /* 423 */
- { 91, 6, 12, 0, 0, 91, 0, }, /* 424 */
- { 28, 11, 3, 0, 0, 28, 0, }, /* 425 */
- { 62, 12, 3, 0, 0, 62, 0, }, /* 426 */
- { 62, 10, 5, 0, 0, 62, 0, }, /* 427 */
- { 62, 7, 12, 0, 0, 62, 0, }, /* 428 */
- { 62, 10, 3, 0, 0, 62, 0, }, /* 429 */
- { 62, 13, 12, 0, 0, 62, 0, }, /* 430 */
- { 62, 21, 12, 0, 0, 62, 0, }, /* 431 */
- { 62, 26, 12, 0, 0, 62, 0, }, /* 432 */
- { 76, 12, 3, 0, 0, 76, 0, }, /* 433 */
- { 76, 10, 5, 0, 0, 76, 0, }, /* 434 */
- { 76, 7, 12, 0, 0, 76, 0, }, /* 435 */
- { 76, 13, 12, 0, 0, 76, 0, }, /* 436 */
- { 93, 7, 12, 0, 0, 93, 0, }, /* 437 */
- { 93, 12, 3, 0, 0, 93, 0, }, /* 438 */
- { 93, 10, 5, 0, 0, 93, 0, }, /* 439 */
- { 93, 21, 12, 0, 0, 93, 0, }, /* 440 */
- { 70, 7, 12, 0, 0, 70, 0, }, /* 441 */
- { 70, 10, 5, 0, 0, 70, 0, }, /* 442 */
- { 70, 12, 3, 0, 0, 70, 0, }, /* 443 */
- { 70, 21, 12, 0, 0, 70, 0, }, /* 444 */
- { 70, 13, 12, 0, 0, 70, 0, }, /* 445 */
- { 73, 13, 12, 0, 0, 73, 0, }, /* 446 */
- { 73, 7, 12, 0, 0, 73, 0, }, /* 447 */
- { 73, 6, 12, 0, 0, 73, 0, }, /* 448 */
- { 73, 21, 12, 0, 0, 73, 0, }, /* 449 */
- { 13, 5, 12, 63, -6222, 13, 0, }, /* 450 */
- { 13, 5, 12, 67, -6221, 13, 0, }, /* 451 */
- { 13, 5, 12, 71, -6212, 13, 0, }, /* 452 */
- { 13, 5, 12, 75, -6210, 13, 0, }, /* 453 */
- { 13, 5, 12, 79, -6210, 13, 0, }, /* 454 */
- { 13, 5, 12, 79, -6211, 13, 0, }, /* 455 */
- { 13, 5, 12, 84, -6204, 13, 0, }, /* 456 */
- { 13, 5, 12, 88, -6180, 13, 0, }, /* 457 */
- { 13, 5, 12, 108, 35267, 13, 0, }, /* 458 */
- { 17, 9, 12, 0, -3008, 17, 0, }, /* 459 */
- { 76, 21, 12, 0, 0, 76, 0, }, /* 460 */
- { 28, 12, 3, 0, 0, -112, 0, }, /* 461 */
- { 28, 12, 3, 0, 0, 15, 0, }, /* 462 */
- { 10, 21, 12, 0, 0, -37, 0, }, /* 463 */
- { 28, 12, 3, 0, 0, -13, 0, }, /* 464 */
- { 28, 12, 3, 0, 0, -43, 0, }, /* 465 */
- { 28, 12, 3, 0, 0, -146, 0, }, /* 466 */
- { 10, 10, 5, 0, 0, -13, 0, }, /* 467 */
- { 10, 7, 12, 0, 0, -40, 0, }, /* 468 */
- { 10, 7, 12, 0, 0, -13, 0, }, /* 469 */
- { 10, 7, 12, 0, 0, 15, 0, }, /* 470 */
- { 10, 7, 12, 0, 0, -162, 0, }, /* 471 */
- { 10, 7, 12, 0, 0, -37, 0, }, /* 472 */
- { 28, 12, 3, 0, 0, -96, 0, }, /* 473 */
- { 10, 10, 5, 0, 0, 3, 0, }, /* 474 */
- { 28, 12, 3, 0, 0, -37, 0, }, /* 475 */
- { 10, 7, 12, 0, 0, 150, 0, }, /* 476 */
- { 13, 5, 12, 0, 0, 13, 0, }, /* 477 */
- { 13, 6, 12, 0, 0, 13, 0, }, /* 478 */
- { 34, 5, 12, 0, 35332, 34, 0, }, /* 479 */
- { 34, 5, 12, 0, 3814, 34, 0, }, /* 480 */
- { 34, 5, 12, 0, 35384, 34, 0, }, /* 481 */
- { 28, 12, 3, 0, 0, -34, 0, }, /* 482 */
- { 34, 9, 12, 92, 1, 34, 0, }, /* 483 */
- { 34, 5, 12, 92, -1, 34, 0, }, /* 484 */
- { 34, 5, 12, 92, -58, 34, 0, }, /* 485 */
- { 34, 9, 12, 0, -7615, 34, 0, }, /* 486 */
- { 20, 5, 12, 0, 8, 20, 0, }, /* 487 */
- { 20, 9, 12, 0, -8, 20, 0, }, /* 488 */
- { 20, 5, 12, 0, 74, 20, 0, }, /* 489 */
- { 20, 5, 12, 0, 86, 20, 0, }, /* 490 */
- { 20, 5, 12, 0, 100, 20, 0, }, /* 491 */
- { 20, 5, 12, 0, 128, 20, 0, }, /* 492 */
- { 20, 5, 12, 0, 112, 20, 0, }, /* 493 */
- { 20, 5, 12, 0, 126, 20, 0, }, /* 494 */
- { 20, 8, 12, 0, -8, 20, 0, }, /* 495 */
- { 20, 5, 12, 0, 9, 20, 0, }, /* 496 */
- { 20, 9, 12, 0, -74, 20, 0, }, /* 497 */
- { 20, 8, 12, 0, -9, 20, 0, }, /* 498 */
- { 20, 5, 12, 21, -7173, 20, 0, }, /* 499 */
- { 20, 9, 12, 0, -86, 20, 0, }, /* 500 */
- { 20, 9, 12, 0, -100, 20, 0, }, /* 501 */
- { 20, 9, 12, 0, -112, 20, 0, }, /* 502 */
- { 20, 9, 12, 0, -128, 20, 0, }, /* 503 */
- { 20, 9, 12, 0, -126, 20, 0, }, /* 504 */
- { 28, 1, 3, 0, 0, 28, 0, }, /* 505 */
- { 28, 1, 13, 0, 0, 28, 0, }, /* 506 */
- { 10, 27, 2, 0, 0, 10, 0, }, /* 507 */
- { 10, 28, 2, 0, 0, 10, 0, }, /* 508 */
- { 10, 29, 12, 0, 0, -70, 0, }, /* 509 */
- { 10, 21, 14, 0, 0, 10, 0, }, /* 510 */
- { 0, 2, 2, 0, 0, 0, 0, }, /* 511 */
- { 28, 12, 3, 0, 0, -100, 0, }, /* 512 */
- { 10, 9, 12, 0, 0, 10, 0, }, /* 513 */
- { 10, 5, 12, 0, 0, 10, 0, }, /* 514 */
- { 20, 9, 12, 96, -7517, 20, 0, }, /* 515 */
- { 34, 9, 12, 100, -8383, 34, 0, }, /* 516 */
- { 34, 9, 12, 104, -8262, 34, 0, }, /* 517 */
- { 34, 9, 12, 0, 28, 34, 0, }, /* 518 */
- { 10, 7, 12, 0, 0, 10, 0, }, /* 519 */
- { 10, 5, 14, 0, 0, 10, 0, }, /* 520 */
- { 34, 5, 12, 0, -28, 34, 0, }, /* 521 */
- { 34, 14, 12, 0, 16, 34, 0, }, /* 522 */
- { 34, 14, 12, 0, -16, 34, 0, }, /* 523 */
- { 34, 14, 12, 0, 0, 34, 0, }, /* 524 */
- { 10, 25, 14, 0, 0, 10, 0, }, /* 525 */
- { 10, 26, 12, 0, 26, 10, 0, }, /* 526 */
- { 10, 26, 14, 0, 26, 10, 0, }, /* 527 */
- { 10, 26, 12, 0, -26, 10, 0, }, /* 528 */
- { 5, 26, 12, 0, 0, 5, 0, }, /* 529 */
- { 18, 9, 12, 0, 48, 18, 0, }, /* 530 */
- { 18, 5, 12, 0, -48, 18, 0, }, /* 531 */
- { 34, 9, 12, 0, -10743, 34, 0, }, /* 532 */
- { 34, 9, 12, 0, -3814, 34, 0, }, /* 533 */
- { 34, 9, 12, 0, -10727, 34, 0, }, /* 534 */
- { 34, 5, 12, 0, -10795, 34, 0, }, /* 535 */
- { 34, 5, 12, 0, -10792, 34, 0, }, /* 536 */
- { 34, 9, 12, 0, -10780, 34, 0, }, /* 537 */
- { 34, 9, 12, 0, -10749, 34, 0, }, /* 538 */
- { 34, 9, 12, 0, -10783, 34, 0, }, /* 539 */
- { 34, 9, 12, 0, -10782, 34, 0, }, /* 540 */
- { 34, 9, 12, 0, -10815, 34, 0, }, /* 541 */
- { 11, 5, 12, 0, 0, 11, 0, }, /* 542 */
- { 11, 26, 12, 0, 0, 11, 0, }, /* 543 */
- { 11, 12, 3, 0, 0, 11, 0, }, /* 544 */
- { 11, 21, 12, 0, 0, 11, 0, }, /* 545 */
- { 11, 15, 12, 0, 0, 11, 0, }, /* 546 */
- { 17, 5, 12, 0, -7264, 17, 0, }, /* 547 */
- { 59, 7, 12, 0, 0, 59, 0, }, /* 548 */
- { 59, 6, 12, 0, 0, 59, 0, }, /* 549 */
- { 59, 21, 12, 0, 0, 59, 0, }, /* 550 */
- { 59, 12, 3, 0, 0, 59, 0, }, /* 551 */
- { 13, 12, 3, 0, 0, 13, 0, }, /* 552 */
- { 10, 21, 12, 0, 0, -25, 0, }, /* 553 */
- { 23, 26, 12, 0, 0, 23, 0, }, /* 554 */
- { 10, 21, 12, 0, 0, -139, 0, }, /* 555 */
- { 10, 21, 12, 0, 0, -133, 0, }, /* 556 */
- { 23, 6, 12, 0, 0, 23, 0, }, /* 557 */
- { 10, 7, 12, 0, 0, 23, 0, }, /* 558 */
- { 23, 14, 12, 0, 0, 23, 0, }, /* 559 */
- { 10, 22, 12, 0, 0, -139, 0, }, /* 560 */
- { 10, 18, 12, 0, 0, -139, 0, }, /* 561 */
- { 10, 26, 12, 0, 0, -133, 0, }, /* 562 */
- { 10, 17, 12, 0, 0, -133, 0, }, /* 563 */
- { 10, 22, 12, 0, 0, -133, 0, }, /* 564 */
- { 10, 18, 12, 0, 0, -133, 0, }, /* 565 */
- { 28, 12, 3, 0, 0, -16, 0, }, /* 566 */
- { 24, 10, 3, 0, 0, 24, 0, }, /* 567 */
- { 10, 17, 14, 0, 0, -133, 0, }, /* 568 */
- { 10, 6, 12, 0, 0, -64, 0, }, /* 569 */
- { 10, 7, 12, 0, 0, -104, 0, }, /* 570 */
- { 10, 21, 14, 0, 0, -104, 0, }, /* 571 */
- { 10, 26, 12, 0, 0, 23, 0, }, /* 572 */
- { 27, 7, 12, 0, 0, 27, 0, }, /* 573 */
- { 28, 12, 3, 0, 0, -64, 0, }, /* 574 */
- { 10, 24, 12, 0, 0, -64, 0, }, /* 575 */
- { 27, 6, 12, 0, 0, 27, 0, }, /* 576 */
- { 10, 17, 12, 0, 0, -64, 0, }, /* 577 */
- { 30, 7, 12, 0, 0, 30, 0, }, /* 578 */
- { 30, 6, 12, 0, 0, 30, 0, }, /* 579 */
- { 4, 7, 12, 0, 0, 4, 0, }, /* 580 */
- { 24, 7, 12, 0, 0, 24, 0, }, /* 581 */
- { 10, 15, 12, 0, 0, 23, 0, }, /* 582 */
- { 24, 26, 12, 0, 0, 24, 0, }, /* 583 */
- { 10, 26, 14, 0, 0, 23, 0, }, /* 584 */
- { 30, 26, 12, 0, 0, 30, 0, }, /* 585 */
- { 23, 7, 12, 0, 0, 23, 0, }, /* 586 */
- { 61, 7, 12, 0, 0, 61, 0, }, /* 587 */
- { 61, 6, 12, 0, 0, 61, 0, }, /* 588 */
- { 61, 26, 12, 0, 0, 61, 0, }, /* 589 */
- { 86, 7, 12, 0, 0, 86, 0, }, /* 590 */
- { 86, 6, 12, 0, 0, 86, 0, }, /* 591 */
- { 86, 21, 12, 0, 0, 86, 0, }, /* 592 */
- { 77, 7, 12, 0, 0, 77, 0, }, /* 593 */
- { 77, 6, 12, 0, 0, 77, 0, }, /* 594 */
- { 77, 21, 12, 0, 0, 77, 0, }, /* 595 */
- { 77, 13, 12, 0, 0, 77, 0, }, /* 596 */
- { 13, 9, 12, 108, 1, 13, 0, }, /* 597 */
- { 13, 5, 12, 108, -35267, 13, 0, }, /* 598 */
- { 13, 7, 12, 0, 0, 13, 0, }, /* 599 */
- { 13, 21, 12, 0, 0, 13, 0, }, /* 600 */
- { 79, 7, 12, 0, 0, 79, 0, }, /* 601 */
- { 79, 14, 12, 0, 0, 79, 0, }, /* 602 */
- { 79, 12, 3, 0, 0, 79, 0, }, /* 603 */
- { 79, 21, 12, 0, 0, 79, 0, }, /* 604 */
- { 10, 24, 12, 0, 0, -61, 0, }, /* 605 */
- { 34, 9, 12, 0, -35332, 34, 0, }, /* 606 */
- { 34, 9, 12, 0, -42280, 34, 0, }, /* 607 */
- { 34, 5, 12, 0, 48, 34, 0, }, /* 608 */
- { 34, 9, 12, 0, -42308, 34, 0, }, /* 609 */
- { 34, 9, 12, 0, -42319, 34, 0, }, /* 610 */
- { 34, 9, 12, 0, -42315, 34, 0, }, /* 611 */
- { 34, 9, 12, 0, -42305, 34, 0, }, /* 612 */
- { 34, 9, 12, 0, -42258, 34, 0, }, /* 613 */
- { 34, 9, 12, 0, -42282, 34, 0, }, /* 614 */
- { 34, 9, 12, 0, -42261, 34, 0, }, /* 615 */
- { 34, 9, 12, 0, 928, 34, 0, }, /* 616 */
- { 34, 9, 12, 0, -48, 34, 0, }, /* 617 */
- { 34, 9, 12, 0, -42307, 34, 0, }, /* 618 */
- { 34, 9, 12, 0, -35384, 34, 0, }, /* 619 */
- { 49, 7, 12, 0, 0, 49, 0, }, /* 620 */
- { 49, 12, 3, 0, 0, 49, 0, }, /* 621 */
- { 49, 10, 5, 0, 0, 49, 0, }, /* 622 */
- { 49, 26, 12, 0, 0, 49, 0, }, /* 623 */
- { 10, 15, 12, 0, 0, -224, 0, }, /* 624 */
- { 10, 15, 12, 0, 0, -210, 0, }, /* 625 */
- { 10, 26, 12, 0, 0, -171, 0, }, /* 626 */
- { 10, 23, 12, 0, 0, -171, 0, }, /* 627 */
- { 65, 7, 12, 0, 0, 65, 0, }, /* 628 */
- { 65, 21, 12, 0, 0, 65, 0, }, /* 629 */
- { 75, 10, 5, 0, 0, 75, 0, }, /* 630 */
- { 75, 7, 12, 0, 0, 75, 0, }, /* 631 */
- { 75, 12, 3, 0, 0, 75, 0, }, /* 632 */
- { 75, 21, 12, 0, 0, 75, 0, }, /* 633 */
- { 75, 13, 12, 0, 0, 75, 0, }, /* 634 */
- { 15, 12, 3, 0, 0, -13, 0, }, /* 635 */
- { 15, 7, 12, 0, 0, -46, 0, }, /* 636 */
- { 69, 13, 12, 0, 0, 69, 0, }, /* 637 */
- { 69, 7, 12, 0, 0, 69, 0, }, /* 638 */
- { 69, 12, 3, 0, 0, 69, 0, }, /* 639 */
- { 10, 21, 12, 0, 0, -108, 0, }, /* 640 */
- { 69, 21, 12, 0, 0, 69, 0, }, /* 641 */
- { 74, 7, 12, 0, 0, 74, 0, }, /* 642 */
- { 74, 12, 3, 0, 0, 74, 0, }, /* 643 */
- { 74, 10, 5, 0, 0, 74, 0, }, /* 644 */
- { 74, 21, 12, 0, 0, 74, 0, }, /* 645 */
- { 84, 12, 3, 0, 0, 84, 0, }, /* 646 */
- { 84, 10, 5, 0, 0, 84, 0, }, /* 647 */
- { 84, 7, 12, 0, 0, 84, 0, }, /* 648 */
- { 84, 21, 12, 0, 0, 84, 0, }, /* 649 */
- { 10, 6, 12, 0, 0, -19, 0, }, /* 650 */
- { 84, 13, 12, 0, 0, 84, 0, }, /* 651 */
- { 39, 6, 12, 0, 0, 39, 0, }, /* 652 */
- { 68, 7, 12, 0, 0, 68, 0, }, /* 653 */
- { 68, 12, 3, 0, 0, 68, 0, }, /* 654 */
- { 68, 10, 5, 0, 0, 68, 0, }, /* 655 */
- { 68, 13, 12, 0, 0, 68, 0, }, /* 656 */
- { 68, 21, 12, 0, 0, 68, 0, }, /* 657 */
- { 92, 7, 12, 0, 0, 92, 0, }, /* 658 */
- { 92, 12, 3, 0, 0, 92, 0, }, /* 659 */
- { 92, 6, 12, 0, 0, 92, 0, }, /* 660 */
- { 92, 21, 12, 0, 0, 92, 0, }, /* 661 */
- { 87, 7, 12, 0, 0, 87, 0, }, /* 662 */
- { 87, 10, 5, 0, 0, 87, 0, }, /* 663 */
- { 87, 12, 3, 0, 0, 87, 0, }, /* 664 */
- { 87, 21, 12, 0, 0, 87, 0, }, /* 665 */
- { 87, 6, 12, 0, 0, 87, 0, }, /* 666 */
- { 34, 5, 12, 0, -928, 34, 0, }, /* 667 */
- { 9, 5, 12, 0, -38864, 9, 0, }, /* 668 */
- { 87, 13, 12, 0, 0, 87, 0, }, /* 669 */
- { 24, 7, 9, 0, 0, 24, 0, }, /* 670 */
- { 24, 7, 10, 0, 0, 24, 0, }, /* 671 */
- { 0, 4, 12, 0, 0, 0, 0, }, /* 672 */
- { 0, 3, 12, 0, 0, 0, 0, }, /* 673 */
- { 26, 25, 12, 0, 0, 26, 0, }, /* 674 */
- { 1, 24, 12, 0, 0, 1, 0, }, /* 675 */
- { 1, 7, 12, 0, 0, -10, 0, }, /* 676 */
- { 1, 26, 12, 0, 0, -10, 0, }, /* 677 */
- { 10, 6, 3, 0, 0, -64, 0, }, /* 678 */
- { 36, 7, 12, 0, 0, 36, 0, }, /* 679 */
- { 10, 21, 12, 0, 0, -22, 0, }, /* 680 */
- { 10, 15, 12, 0, 0, -92, 0, }, /* 681 */
- { 10, 26, 12, 0, 0, -22, 0, }, /* 682 */
- { 20, 14, 12, 0, 0, 20, 0, }, /* 683 */
- { 20, 15, 12, 0, 0, 20, 0, }, /* 684 */
- { 20, 26, 12, 0, 0, 20, 0, }, /* 685 */
- { 71, 7, 12, 0, 0, 71, 0, }, /* 686 */
- { 67, 7, 12, 0, 0, 67, 0, }, /* 687 */
- { 28, 12, 3, 0, 0, -1, 0, }, /* 688 */
- { 10, 15, 12, 0, 0, -1, 0, }, /* 689 */
- { 42, 7, 12, 0, 0, 42, 0, }, /* 690 */
- { 42, 15, 12, 0, 0, 42, 0, }, /* 691 */
- { 19, 7, 12, 0, 0, 19, 0, }, /* 692 */
- { 19, 14, 12, 0, 0, 19, 0, }, /* 693 */
- { 118, 7, 12, 0, 0, 118, 0, }, /* 694 */
- { 118, 12, 3, 0, 0, 118, 0, }, /* 695 */
- { 60, 7, 12, 0, 0, 60, 0, }, /* 696 */
- { 60, 21, 12, 0, 0, 60, 0, }, /* 697 */
- { 43, 7, 12, 0, 0, 43, 0, }, /* 698 */
- { 43, 21, 12, 0, 0, 43, 0, }, /* 699 */
- { 43, 14, 12, 0, 0, 43, 0, }, /* 700 */
- { 14, 9, 12, 0, 40, 14, 0, }, /* 701 */
- { 14, 5, 12, 0, -40, 14, 0, }, /* 702 */
- { 47, 7, 12, 0, 0, 47, 0, }, /* 703 */
- { 45, 7, 12, 0, 0, 45, 0, }, /* 704 */
- { 45, 13, 12, 0, 0, 45, 0, }, /* 705 */
- { 136, 9, 12, 0, 40, 136, 0, }, /* 706 */
- { 136, 5, 12, 0, -40, 136, 0, }, /* 707 */
- { 106, 7, 12, 0, 0, 106, 0, }, /* 708 */
- { 104, 7, 12, 0, 0, 104, 0, }, /* 709 */
- { 104, 21, 12, 0, 0, 104, 0, }, /* 710 */
- { 110, 7, 12, 0, 0, 110, 0, }, /* 711 */
- { 12, 7, 12, 0, 0, 12, 0, }, /* 712 */
- { 81, 7, 12, 0, 0, 81, 0, }, /* 713 */
- { 81, 21, 12, 0, 0, 81, 0, }, /* 714 */
- { 81, 15, 12, 0, 0, 81, 0, }, /* 715 */
- { 120, 7, 12, 0, 0, 120, 0, }, /* 716 */
- { 120, 26, 12, 0, 0, 120, 0, }, /* 717 */
- { 120, 15, 12, 0, 0, 120, 0, }, /* 718 */
- { 116, 7, 12, 0, 0, 116, 0, }, /* 719 */
- { 116, 15, 12, 0, 0, 116, 0, }, /* 720 */
- { 128, 7, 12, 0, 0, 128, 0, }, /* 721 */
- { 128, 15, 12, 0, 0, 128, 0, }, /* 722 */
- { 66, 7, 12, 0, 0, 66, 0, }, /* 723 */
- { 66, 15, 12, 0, 0, 66, 0, }, /* 724 */
- { 66, 21, 12, 0, 0, 66, 0, }, /* 725 */
- { 72, 7, 12, 0, 0, 72, 0, }, /* 726 */
- { 72, 21, 12, 0, 0, 72, 0, }, /* 727 */
- { 98, 7, 12, 0, 0, 98, 0, }, /* 728 */
- { 97, 7, 12, 0, 0, 97, 0, }, /* 729 */
- { 97, 15, 12, 0, 0, 97, 0, }, /* 730 */
- { 31, 7, 12, 0, 0, 31, 0, }, /* 731 */
- { 31, 12, 3, 0, 0, 31, 0, }, /* 732 */
- { 31, 15, 12, 0, 0, 31, 0, }, /* 733 */
- { 31, 21, 12, 0, 0, 31, 0, }, /* 734 */
- { 88, 7, 12, 0, 0, 88, 0, }, /* 735 */
- { 88, 15, 12, 0, 0, 88, 0, }, /* 736 */
- { 88, 21, 12, 0, 0, 88, 0, }, /* 737 */
- { 117, 7, 12, 0, 0, 117, 0, }, /* 738 */
- { 117, 15, 12, 0, 0, 117, 0, }, /* 739 */
- { 112, 7, 12, 0, 0, 112, 0, }, /* 740 */
- { 112, 26, 12, 0, 0, 112, 0, }, /* 741 */
- { 112, 12, 3, 0, 0, 112, 0, }, /* 742 */
- { 112, 15, 12, 0, 0, 112, 0, }, /* 743 */
- { 112, 21, 12, 0, 0, 112, 0, }, /* 744 */
- { 78, 7, 12, 0, 0, 78, 0, }, /* 745 */
- { 78, 21, 12, 0, 0, 78, 0, }, /* 746 */
- { 83, 7, 12, 0, 0, 83, 0, }, /* 747 */
- { 83, 15, 12, 0, 0, 83, 0, }, /* 748 */
- { 82, 7, 12, 0, 0, 82, 0, }, /* 749 */
- { 82, 15, 12, 0, 0, 82, 0, }, /* 750 */
- { 121, 7, 12, 0, 0, 121, 0, }, /* 751 */
- { 121, 21, 12, 0, 0, 121, 0, }, /* 752 */
- { 121, 15, 12, 0, 0, 121, 0, }, /* 753 */
- { 89, 7, 12, 0, 0, 89, 0, }, /* 754 */
- { 130, 9, 12, 0, 64, 130, 0, }, /* 755 */
- { 130, 5, 12, 0, -64, 130, 0, }, /* 756 */
- { 130, 15, 12, 0, 0, 130, 0, }, /* 757 */
- { 144, 7, 12, 0, 0, 144, 0, }, /* 758 */
- { 144, 12, 3, 0, 0, 144, 0, }, /* 759 */
- { 144, 13, 12, 0, 0, 144, 0, }, /* 760 */
- { 1, 15, 12, 0, 0, 1, 0, }, /* 761 */
- { 156, 7, 12, 0, 0, 156, 0, }, /* 762 */
- { 156, 12, 3, 0, 0, 156, 0, }, /* 763 */
- { 156, 17, 12, 0, 0, 156, 0, }, /* 764 */
- { 147, 7, 12, 0, 0, 147, 0, }, /* 765 */
- { 147, 15, 12, 0, 0, 147, 0, }, /* 766 */
- { 148, 7, 12, 0, 0, 148, 0, }, /* 767 */
- { 148, 12, 3, 0, 0, 148, 0, }, /* 768 */
- { 148, 15, 12, 0, 0, 148, 0, }, /* 769 */
- { 148, 21, 12, 0, 0, 148, 0, }, /* 770 */
- { 153, 7, 12, 0, 0, 153, 0, }, /* 771 */
- { 153, 15, 12, 0, 0, 153, 0, }, /* 772 */
- { 149, 7, 12, 0, 0, 149, 0, }, /* 773 */
- { 94, 10, 5, 0, 0, 94, 0, }, /* 774 */
- { 94, 12, 3, 0, 0, 94, 0, }, /* 775 */
- { 94, 7, 12, 0, 0, 94, 0, }, /* 776 */
- { 94, 21, 12, 0, 0, 94, 0, }, /* 777 */
- { 94, 15, 12, 0, 0, 94, 0, }, /* 778 */
- { 94, 13, 12, 0, 0, 94, 0, }, /* 779 */
- { 85, 12, 3, 0, 0, 85, 0, }, /* 780 */
- { 85, 10, 5, 0, 0, 85, 0, }, /* 781 */
- { 85, 7, 12, 0, 0, 85, 0, }, /* 782 */
- { 85, 21, 12, 0, 0, 85, 0, }, /* 783 */
- { 85, 1, 4, 0, 0, 85, 0, }, /* 784 */
- { 101, 7, 12, 0, 0, 101, 0, }, /* 785 */
- { 101, 13, 12, 0, 0, 101, 0, }, /* 786 */
- { 96, 12, 3, 0, 0, 96, 0, }, /* 787 */
- { 96, 7, 12, 0, 0, 96, 0, }, /* 788 */
- { 96, 10, 5, 0, 0, 96, 0, }, /* 789 */
- { 96, 13, 12, 0, 0, 96, 0, }, /* 790 */
- { 96, 21, 12, 0, 0, 96, 0, }, /* 791 */
- { 111, 7, 12, 0, 0, 111, 0, }, /* 792 */
- { 111, 12, 3, 0, 0, 111, 0, }, /* 793 */
- { 111, 21, 12, 0, 0, 111, 0, }, /* 794 */
- { 100, 12, 3, 0, 0, 100, 0, }, /* 795 */
- { 100, 10, 5, 0, 0, 100, 0, }, /* 796 */
- { 100, 7, 12, 0, 0, 100, 0, }, /* 797 */
- { 100, 7, 4, 0, 0, 100, 0, }, /* 798 */
- { 100, 21, 12, 0, 0, 100, 0, }, /* 799 */
- { 100, 13, 12, 0, 0, 100, 0, }, /* 800 */
- { 48, 15, 12, 0, 0, 48, 0, }, /* 801 */
- { 108, 7, 12, 0, 0, 108, 0, }, /* 802 */
- { 108, 10, 5, 0, 0, 108, 0, }, /* 803 */
- { 108, 12, 3, 0, 0, 108, 0, }, /* 804 */
- { 108, 21, 12, 0, 0, 108, 0, }, /* 805 */
- { 129, 7, 12, 0, 0, 129, 0, }, /* 806 */
- { 129, 21, 12, 0, 0, 129, 0, }, /* 807 */
- { 109, 7, 12, 0, 0, 109, 0, }, /* 808 */
- { 109, 12, 3, 0, 0, 109, 0, }, /* 809 */
- { 109, 10, 5, 0, 0, 109, 0, }, /* 810 */
- { 109, 13, 12, 0, 0, 109, 0, }, /* 811 */
- { 107, 12, 3, 0, 0, 107, 0, }, /* 812 */
- { 107, 12, 3, 0, 0, -52, 0, }, /* 813 */
- { 107, 10, 5, 0, 0, 107, 0, }, /* 814 */
- { 107, 10, 5, 0, 0, -52, 0, }, /* 815 */
- { 107, 7, 12, 0, 0, 107, 0, }, /* 816 */
- { 28, 12, 3, 0, 0, -52, 0, }, /* 817 */
- { 107, 10, 3, 0, 0, 107, 0, }, /* 818 */
- { 135, 7, 12, 0, 0, 135, 0, }, /* 819 */
- { 135, 10, 5, 0, 0, 135, 0, }, /* 820 */
- { 135, 12, 3, 0, 0, 135, 0, }, /* 821 */
- { 135, 21, 12, 0, 0, 135, 0, }, /* 822 */
- { 135, 13, 12, 0, 0, 135, 0, }, /* 823 */
- { 124, 7, 12, 0, 0, 124, 0, }, /* 824 */
- { 124, 10, 3, 0, 0, 124, 0, }, /* 825 */
- { 124, 10, 5, 0, 0, 124, 0, }, /* 826 */
- { 124, 12, 3, 0, 0, 124, 0, }, /* 827 */
- { 124, 21, 12, 0, 0, 124, 0, }, /* 828 */
- { 124, 13, 12, 0, 0, 124, 0, }, /* 829 */
- { 123, 7, 12, 0, 0, 123, 0, }, /* 830 */
- { 123, 10, 3, 0, 0, 123, 0, }, /* 831 */
- { 123, 10, 5, 0, 0, 123, 0, }, /* 832 */
- { 123, 12, 3, 0, 0, 123, 0, }, /* 833 */
- { 123, 21, 12, 0, 0, 123, 0, }, /* 834 */
- { 114, 7, 12, 0, 0, 114, 0, }, /* 835 */
- { 114, 10, 5, 0, 0, 114, 0, }, /* 836 */
- { 114, 12, 3, 0, 0, 114, 0, }, /* 837 */
- { 114, 21, 12, 0, 0, 114, 0, }, /* 838 */
- { 114, 13, 12, 0, 0, 114, 0, }, /* 839 */
- { 102, 7, 12, 0, 0, 102, 0, }, /* 840 */
- { 102, 12, 3, 0, 0, 102, 0, }, /* 841 */
- { 102, 10, 5, 0, 0, 102, 0, }, /* 842 */
- { 102, 13, 12, 0, 0, 102, 0, }, /* 843 */
- { 126, 7, 12, 0, 0, 126, 0, }, /* 844 */
- { 126, 12, 3, 0, 0, 126, 0, }, /* 845 */
- { 126, 10, 5, 0, 0, 126, 0, }, /* 846 */
- { 126, 13, 12, 0, 0, 126, 0, }, /* 847 */
- { 126, 15, 12, 0, 0, 126, 0, }, /* 848 */
- { 126, 21, 12, 0, 0, 126, 0, }, /* 849 */
- { 126, 26, 12, 0, 0, 126, 0, }, /* 850 */
- { 142, 7, 12, 0, 0, 142, 0, }, /* 851 */
- { 142, 10, 5, 0, 0, 142, 0, }, /* 852 */
- { 142, 12, 3, 0, 0, 142, 0, }, /* 853 */
- { 142, 21, 12, 0, 0, 142, 0, }, /* 854 */
- { 125, 9, 12, 0, 32, 125, 0, }, /* 855 */
- { 125, 5, 12, 0, -32, 125, 0, }, /* 856 */
- { 125, 13, 12, 0, 0, 125, 0, }, /* 857 */
- { 125, 15, 12, 0, 0, 125, 0, }, /* 858 */
- { 125, 7, 12, 0, 0, 125, 0, }, /* 859 */
- { 154, 7, 12, 0, 0, 154, 0, }, /* 860 */
- { 154, 10, 3, 0, 0, 154, 0, }, /* 861 */
- { 154, 10, 5, 0, 0, 154, 0, }, /* 862 */
- { 154, 12, 3, 0, 0, 154, 0, }, /* 863 */
- { 154, 7, 4, 0, 0, 154, 0, }, /* 864 */
- { 154, 21, 12, 0, 0, 154, 0, }, /* 865 */
- { 154, 13, 12, 0, 0, 154, 0, }, /* 866 */
- { 150, 7, 12, 0, 0, 150, 0, }, /* 867 */
- { 150, 10, 5, 0, 0, 150, 0, }, /* 868 */
- { 150, 12, 3, 0, 0, 150, 0, }, /* 869 */
- { 150, 21, 12, 0, 0, 150, 0, }, /* 870 */
- { 141, 7, 12, 0, 0, 141, 0, }, /* 871 */
- { 141, 12, 3, 0, 0, 141, 0, }, /* 872 */
- { 141, 10, 5, 0, 0, 141, 0, }, /* 873 */
- { 141, 7, 4, 0, 0, 141, 0, }, /* 874 */
- { 141, 21, 12, 0, 0, 141, 0, }, /* 875 */
- { 140, 7, 12, 0, 0, 140, 0, }, /* 876 */
- { 140, 12, 3, 0, 0, 140, 0, }, /* 877 */
- { 140, 10, 5, 0, 0, 140, 0, }, /* 878 */
- { 140, 7, 4, 0, 0, 140, 0, }, /* 879 */
- { 140, 21, 12, 0, 0, 140, 0, }, /* 880 */
- { 122, 7, 12, 0, 0, 122, 0, }, /* 881 */
- { 133, 7, 12, 0, 0, 133, 0, }, /* 882 */
- { 133, 10, 5, 0, 0, 133, 0, }, /* 883 */
- { 133, 12, 3, 0, 0, 133, 0, }, /* 884 */
- { 133, 21, 12, 0, 0, 133, 0, }, /* 885 */
- { 133, 13, 12, 0, 0, 133, 0, }, /* 886 */
- { 133, 15, 12, 0, 0, 133, 0, }, /* 887 */
- { 134, 21, 12, 0, 0, 134, 0, }, /* 888 */
- { 134, 7, 12, 0, 0, 134, 0, }, /* 889 */
- { 134, 12, 3, 0, 0, 134, 0, }, /* 890 */
- { 134, 10, 5, 0, 0, 134, 0, }, /* 891 */
- { 138, 7, 12, 0, 0, 138, 0, }, /* 892 */
- { 138, 12, 3, 0, 0, 138, 0, }, /* 893 */
- { 138, 7, 4, 0, 0, 138, 0, }, /* 894 */
- { 138, 13, 12, 0, 0, 138, 0, }, /* 895 */
- { 143, 7, 12, 0, 0, 143, 0, }, /* 896 */
- { 143, 10, 5, 0, 0, 143, 0, }, /* 897 */
- { 143, 12, 3, 0, 0, 143, 0, }, /* 898 */
- { 143, 13, 12, 0, 0, 143, 0, }, /* 899 */
- { 145, 7, 12, 0, 0, 145, 0, }, /* 900 */
- { 145, 12, 3, 0, 0, 145, 0, }, /* 901 */
- { 145, 10, 5, 0, 0, 145, 0, }, /* 902 */
- { 145, 21, 12, 0, 0, 145, 0, }, /* 903 */
- { 54, 15, 12, 0, 0, 54, 0, }, /* 904 */
- { 54, 21, 12, 0, 0, 54, 0, }, /* 905 */
- { 63, 7, 12, 0, 0, 63, 0, }, /* 906 */
- { 63, 14, 12, 0, 0, 63, 0, }, /* 907 */
- { 63, 21, 12, 0, 0, 63, 0, }, /* 908 */
- { 80, 7, 12, 0, 0, 80, 0, }, /* 909 */
- { 80, 1, 2, 0, 0, 80, 0, }, /* 910 */
- { 127, 7, 12, 0, 0, 127, 0, }, /* 911 */
- { 115, 7, 12, 0, 0, 115, 0, }, /* 912 */
- { 115, 13, 12, 0, 0, 115, 0, }, /* 913 */
- { 115, 21, 12, 0, 0, 115, 0, }, /* 914 */
- { 103, 7, 12, 0, 0, 103, 0, }, /* 915 */
- { 103, 12, 3, 0, 0, 103, 0, }, /* 916 */
- { 103, 21, 12, 0, 0, 103, 0, }, /* 917 */
- { 119, 7, 12, 0, 0, 119, 0, }, /* 918 */
- { 119, 12, 3, 0, 0, 119, 0, }, /* 919 */
- { 119, 21, 12, 0, 0, 119, 0, }, /* 920 */
- { 119, 26, 12, 0, 0, 119, 0, }, /* 921 */
- { 119, 6, 12, 0, 0, 119, 0, }, /* 922 */
- { 119, 13, 12, 0, 0, 119, 0, }, /* 923 */
- { 119, 15, 12, 0, 0, 119, 0, }, /* 924 */
- { 146, 9, 12, 0, 32, 146, 0, }, /* 925 */
- { 146, 5, 12, 0, -32, 146, 0, }, /* 926 */
- { 146, 15, 12, 0, 0, 146, 0, }, /* 927 */
- { 146, 21, 12, 0, 0, 146, 0, }, /* 928 */
- { 99, 7, 12, 0, 0, 99, 0, }, /* 929 */
- { 99, 12, 3, 0, 0, 99, 0, }, /* 930 */
- { 99, 10, 5, 0, 0, 99, 0, }, /* 931 */
- { 99, 6, 12, 0, 0, 99, 0, }, /* 932 */
- { 137, 6, 12, 0, 0, 137, 0, }, /* 933 */
- { 139, 6, 12, 0, 0, 139, 0, }, /* 934 */
- { 155, 12, 3, 0, 0, 155, 0, }, /* 935 */
- { 23, 10, 5, 0, 0, 23, 0, }, /* 936 */
- { 137, 7, 12, 0, 0, 137, 0, }, /* 937 */
- { 155, 7, 12, 0, 0, 155, 0, }, /* 938 */
- { 139, 7, 12, 0, 0, 139, 0, }, /* 939 */
- { 105, 7, 12, 0, 0, 105, 0, }, /* 940 */
- { 105, 26, 12, 0, 0, 105, 0, }, /* 941 */
- { 105, 12, 3, 0, 0, 105, 0, }, /* 942 */
- { 105, 21, 12, 0, 0, 105, 0, }, /* 943 */
- { 10, 1, 2, 0, 0, 105, 0, }, /* 944 */
- { 10, 10, 3, 0, 0, 10, 0, }, /* 945 */
- { 10, 10, 5, 0, 0, 10, 0, }, /* 946 */
- { 20, 12, 3, 0, 0, 20, 0, }, /* 947 */
- { 131, 26, 12, 0, 0, 131, 0, }, /* 948 */
- { 131, 12, 3, 0, 0, 131, 0, }, /* 949 */
- { 131, 21, 12, 0, 0, 131, 0, }, /* 950 */
- { 18, 12, 3, 0, 0, 18, 0, }, /* 951 */
- { 151, 7, 12, 0, 0, 151, 0, }, /* 952 */
- { 151, 12, 3, 0, 0, 151, 0, }, /* 953 */
- { 151, 6, 12, 0, 0, 151, 0, }, /* 954 */
- { 151, 13, 12, 0, 0, 151, 0, }, /* 955 */
- { 151, 26, 12, 0, 0, 151, 0, }, /* 956 */
- { 152, 7, 12, 0, 0, 152, 0, }, /* 957 */
- { 152, 12, 3, 0, 0, 152, 0, }, /* 958 */
- { 152, 13, 12, 0, 0, 152, 0, }, /* 959 */
- { 152, 23, 12, 0, 0, 152, 0, }, /* 960 */
- { 113, 7, 12, 0, 0, 113, 0, }, /* 961 */
- { 113, 15, 12, 0, 0, 113, 0, }, /* 962 */
- { 113, 12, 3, 0, 0, 113, 0, }, /* 963 */
- { 132, 9, 12, 0, 34, 132, 0, }, /* 964 */
- { 132, 5, 12, 0, -34, 132, 0, }, /* 965 */
- { 132, 12, 3, 0, 0, 132, 0, }, /* 966 */
- { 132, 6, 12, 0, 0, 132, 0, }, /* 967 */
- { 132, 13, 12, 0, 0, 132, 0, }, /* 968 */
- { 132, 21, 12, 0, 0, 132, 0, }, /* 969 */
- { 0, 2, 14, 0, 0, 0, 0, }, /* 970 */
- { 10, 26, 11, 0, 0, 10, 0, }, /* 971 */
- { 27, 26, 12, 0, 0, 27, 0, }, /* 972 */
- { 10, 24, 3, 0, 0, 10, 0, }, /* 973 */
- { 10, 1, 3, 0, 0, 10, 0, }, /* 974 */
+ { 1, 1, 2, 0, 0, -82, 0, }, /* 223 */
+ { 10, 21, 12, 0, 0, -164, 0, }, /* 224 */
+ { 1, 7, 12, 0, 0, 1, 0, }, /* 225 */
+ { 10, 6, 12, 0, 0, -181, 0, }, /* 226 */
+ { 28, 12, 3, 0, 0, -10, 0, }, /* 227 */
+ { 1, 13, 12, 0, 0, -86, 0, }, /* 228 */
+ { 1, 21, 12, 0, 0, -4, 0, }, /* 229 */
+ { 1, 6, 12, 0, 0, 1, 0, }, /* 230 */
+ { 1, 13, 12, 0, 0, 1, 0, }, /* 231 */
+ { 50, 21, 12, 0, 0, 50, 0, }, /* 232 */
+ { 50, 1, 4, 0, 0, 50, 0, }, /* 233 */
+ { 50, 7, 12, 0, 0, 50, 0, }, /* 234 */
+ { 50, 12, 3, 0, 0, 50, 0, }, /* 235 */
+ { 56, 7, 12, 0, 0, 56, 0, }, /* 236 */
+ { 56, 12, 3, 0, 0, 56, 0, }, /* 237 */
+ { 64, 13, 12, 0, 0, 64, 0, }, /* 238 */
+ { 64, 7, 12, 0, 0, 64, 0, }, /* 239 */
+ { 64, 12, 3, 0, 0, 64, 0, }, /* 240 */
+ { 64, 6, 12, 0, 0, 64, 0, }, /* 241 */
+ { 64, 26, 12, 0, 0, 64, 0, }, /* 242 */
+ { 64, 21, 12, 0, 0, 64, 0, }, /* 243 */
+ { 64, 23, 12, 0, 0, 64, 0, }, /* 244 */
+ { 90, 7, 12, 0, 0, 90, 0, }, /* 245 */
+ { 90, 12, 3, 0, 0, 90, 0, }, /* 246 */
+ { 90, 6, 12, 0, 0, 90, 0, }, /* 247 */
+ { 90, 21, 12, 0, 0, 90, 0, }, /* 248 */
+ { 95, 7, 12, 0, 0, 95, 0, }, /* 249 */
+ { 95, 12, 3, 0, 0, 95, 0, }, /* 250 */
+ { 95, 21, 12, 0, 0, 95, 0, }, /* 251 */
+ { 1, 24, 12, 0, 0, 1, 0, }, /* 252 */
+ { 15, 12, 3, 0, 0, 15, 0, }, /* 253 */
+ { 15, 10, 5, 0, 0, 15, 0, }, /* 254 */
+ { 15, 7, 12, 0, 0, 15, 0, }, /* 255 */
+ { 28, 12, 3, 0, 0, -216, 0, }, /* 256 */
+ { 28, 12, 3, 0, 0, -203, 0, }, /* 257 */
+ { 10, 21, 12, 0, 0, -259, 0, }, /* 258 */
+ { 10, 21, 12, 0, 0, -280, 0, }, /* 259 */
+ { 15, 13, 12, 0, 0, -132, 0, }, /* 260 */
+ { 15, 21, 12, 0, 0, 15, 0, }, /* 261 */
+ { 15, 6, 12, 0, 0, 15, 0, }, /* 262 */
+ { 3, 7, 12, 0, 0, 3, 0, }, /* 263 */
+ { 3, 12, 3, 0, 0, 3, 0, }, /* 264 */
+ { 3, 10, 5, 0, 0, 3, 0, }, /* 265 */
+ { 3, 10, 3, 0, 0, 3, 0, }, /* 266 */
+ { 3, 13, 12, 0, 0, -90, 0, }, /* 267 */
+ { 3, 23, 12, 0, 0, 3, 0, }, /* 268 */
+ { 3, 15, 12, 0, 0, 3, 0, }, /* 269 */
+ { 3, 26, 12, 0, 0, 3, 0, }, /* 270 */
+ { 3, 21, 12, 0, 0, 3, 0, }, /* 271 */
+ { 22, 12, 3, 0, 0, 22, 0, }, /* 272 */
+ { 22, 10, 5, 0, 0, 22, 0, }, /* 273 */
+ { 22, 7, 12, 0, 0, 22, 0, }, /* 274 */
+ { 22, 13, 12, 0, 0, -61, 0, }, /* 275 */
+ { 22, 21, 12, 0, 0, 22, 0, }, /* 276 */
+ { 21, 12, 3, 0, 0, 21, 0, }, /* 277 */
+ { 21, 10, 5, 0, 0, 21, 0, }, /* 278 */
+ { 21, 7, 12, 0, 0, 21, 0, }, /* 279 */
+ { 21, 13, 12, 0, 0, -58, 0, }, /* 280 */
+ { 21, 21, 12, 0, 0, 21, 0, }, /* 281 */
+ { 21, 23, 12, 0, 0, 21, 0, }, /* 282 */
+ { 44, 12, 3, 0, 0, 44, 0, }, /* 283 */
+ { 44, 10, 5, 0, 0, 44, 0, }, /* 284 */
+ { 44, 7, 12, 0, 0, 44, 0, }, /* 285 */
+ { 44, 10, 3, 0, 0, 44, 0, }, /* 286 */
+ { 44, 13, 12, 0, 0, 44, 0, }, /* 287 */
+ { 44, 26, 12, 0, 0, 44, 0, }, /* 288 */
+ { 44, 15, 12, 0, 0, 44, 0, }, /* 289 */
+ { 54, 12, 3, 0, 0, 54, 0, }, /* 290 */
+ { 54, 7, 12, 0, 0, 54, 0, }, /* 291 */
+ { 54, 10, 3, 0, 0, 54, 0, }, /* 292 */
+ { 54, 10, 5, 0, 0, 54, 0, }, /* 293 */
+ { 54, 13, 12, 0, 0, -55, 0, }, /* 294 */
+ { 54, 15, 12, 0, 0, -55, 0, }, /* 295 */
+ { 54, 26, 12, 0, 0, -55, 0, }, /* 296 */
+ { 54, 26, 12, 0, 0, 54, 0, }, /* 297 */
+ { 54, 23, 12, 0, 0, 54, 0, }, /* 298 */
+ { 55, 12, 3, 0, 0, 55, 0, }, /* 299 */
+ { 55, 10, 5, 0, 0, 55, 0, }, /* 300 */
+ { 55, 7, 12, 0, 0, 55, 0, }, /* 301 */
+ { 55, 13, 12, 0, 0, 55, 0, }, /* 302 */
+ { 55, 21, 12, 0, 0, 55, 0, }, /* 303 */
+ { 55, 15, 12, 0, 0, 55, 0, }, /* 304 */
+ { 55, 26, 12, 0, 0, 55, 0, }, /* 305 */
+ { 29, 7, 12, 0, 0, 29, 0, }, /* 306 */
+ { 29, 12, 3, 0, 0, 29, 0, }, /* 307 */
+ { 29, 10, 5, 0, 0, 29, 0, }, /* 308 */
+ { 29, 21, 12, 0, 0, 29, 0, }, /* 309 */
+ { 29, 10, 3, 0, 0, 29, 0, }, /* 310 */
+ { 29, 13, 12, 0, 0, -70, 0, }, /* 311 */
+ { 37, 12, 3, 0, 0, 37, 0, }, /* 312 */
+ { 37, 10, 5, 0, 0, 37, 0, }, /* 313 */
+ { 37, 7, 12, 0, 0, 37, 0, }, /* 314 */
+ { 37, 10, 3, 0, 0, 37, 0, }, /* 315 */
+ { 37, 7, 4, 0, 0, 37, 0, }, /* 316 */
+ { 37, 26, 12, 0, 0, 37, 0, }, /* 317 */
+ { 37, 15, 12, 0, 0, 37, 0, }, /* 318 */
+ { 37, 13, 12, 0, 0, 37, 0, }, /* 319 */
+ { 48, 12, 3, 0, 0, 48, 0, }, /* 320 */
+ { 48, 10, 5, 0, 0, 48, 0, }, /* 321 */
+ { 48, 7, 12, 0, 0, 48, 0, }, /* 322 */
+ { 48, 10, 3, 0, 0, 48, 0, }, /* 323 */
+ { 48, 13, 12, 0, 0, 48, 0, }, /* 324 */
+ { 48, 21, 12, 0, 0, 48, 0, }, /* 325 */
+ { 57, 7, 12, 0, 0, 57, 0, }, /* 326 */
+ { 57, 12, 3, 0, 0, 57, 0, }, /* 327 */
+ { 57, 7, 5, 0, 0, 57, 0, }, /* 328 */
+ { 57, 6, 12, 0, 0, 57, 0, }, /* 329 */
+ { 57, 21, 12, 0, 0, 57, 0, }, /* 330 */
+ { 57, 13, 12, 0, 0, 57, 0, }, /* 331 */
+ { 33, 7, 12, 0, 0, 33, 0, }, /* 332 */
+ { 33, 12, 3, 0, 0, 33, 0, }, /* 333 */
+ { 33, 7, 5, 0, 0, 33, 0, }, /* 334 */
+ { 33, 6, 12, 0, 0, 33, 0, }, /* 335 */
+ { 33, 13, 12, 0, 0, 33, 0, }, /* 336 */
+ { 58, 7, 12, 0, 0, 58, 0, }, /* 337 */
+ { 58, 26, 12, 0, 0, 58, 0, }, /* 338 */
+ { 58, 21, 12, 0, 0, 58, 0, }, /* 339 */
+ { 58, 12, 3, 0, 0, 58, 0, }, /* 340 */
+ { 58, 13, 12, 0, 0, 58, 0, }, /* 341 */
+ { 58, 15, 12, 0, 0, 58, 0, }, /* 342 */
+ { 58, 22, 12, 0, 0, 58, 0, }, /* 343 */
+ { 58, 18, 12, 0, 0, 58, 0, }, /* 344 */
+ { 58, 10, 5, 0, 0, 58, 0, }, /* 345 */
+ { 39, 7, 12, 0, 0, 39, 0, }, /* 346 */
+ { 39, 10, 12, 0, 0, 39, 0, }, /* 347 */
+ { 39, 12, 3, 0, 0, 39, 0, }, /* 348 */
+ { 39, 10, 5, 0, 0, 39, 0, }, /* 349 */
+ { 39, 13, 12, 0, 0, -94, 0, }, /* 350 */
+ { 39, 21, 12, 0, 0, 39, 0, }, /* 351 */
+ { 39, 13, 12, 0, 0, 39, 0, }, /* 352 */
+ { 39, 26, 12, 0, 0, 39, 0, }, /* 353 */
+ { 17, 9, 12, 0, 7264, 17, 0, }, /* 354 */
+ { 17, 5, 12, 0, 3008, 17, 0, }, /* 355 */
+ { 10, 21, 12, 0, 0, -52, 0, }, /* 356 */
+ { 17, 6, 12, 0, 0, 17, 0, }, /* 357 */
+ { 24, 7, 6, 0, 0, 24, 0, }, /* 358 */
+ { 24, 7, 7, 0, 0, 24, 0, }, /* 359 */
+ { 24, 7, 8, 0, 0, 24, 0, }, /* 360 */
+ { 16, 7, 12, 0, 0, 16, 0, }, /* 361 */
+ { 16, 12, 3, 0, 0, 16, 0, }, /* 362 */
+ { 16, 21, 12, 0, 0, 16, 0, }, /* 363 */
+ { 16, 15, 12, 0, 0, 16, 0, }, /* 364 */
+ { 16, 26, 12, 0, 0, 16, 0, }, /* 365 */
+ { 9, 9, 12, 0, 38864, 9, 0, }, /* 366 */
+ { 9, 9, 12, 0, 8, 9, 0, }, /* 367 */
+ { 9, 5, 12, 0, -8, 9, 0, }, /* 368 */
+ { 8, 17, 12, 0, 0, 8, 0, }, /* 369 */
+ { 8, 7, 12, 0, 0, 8, 0, }, /* 370 */
+ { 8, 26, 12, 0, 0, 8, 0, }, /* 371 */
+ { 8, 21, 12, 0, 0, 8, 0, }, /* 372 */
+ { 41, 29, 12, 0, 0, 41, 0, }, /* 373 */
+ { 41, 7, 12, 0, 0, 41, 0, }, /* 374 */
+ { 41, 22, 12, 0, 0, 41, 0, }, /* 375 */
+ { 41, 18, 12, 0, 0, 41, 0, }, /* 376 */
+ { 46, 7, 12, 0, 0, 46, 0, }, /* 377 */
+ { 46, 14, 12, 0, 0, 46, 0, }, /* 378 */
+ { 51, 7, 12, 0, 0, 51, 0, }, /* 379 */
+ { 51, 12, 3, 0, 0, 51, 0, }, /* 380 */
+ { 51, 10, 5, 0, 0, 51, 0, }, /* 381 */
+ { 25, 7, 12, 0, 0, 25, 0, }, /* 382 */
+ { 25, 12, 3, 0, 0, 25, 0, }, /* 383 */
+ { 25, 10, 5, 0, 0, 25, 0, }, /* 384 */
+ { 10, 21, 12, 0, 0, -127, 0, }, /* 385 */
+ { 7, 7, 12, 0, 0, 7, 0, }, /* 386 */
+ { 7, 12, 3, 0, 0, 7, 0, }, /* 387 */
+ { 52, 7, 12, 0, 0, 52, 0, }, /* 388 */
+ { 52, 12, 3, 0, 0, 52, 0, }, /* 389 */
+ { 32, 7, 12, 0, 0, 32, 0, }, /* 390 */
+ { 32, 12, 3, 0, 0, 32, 0, }, /* 391 */
+ { 32, 10, 5, 0, 0, 32, 0, }, /* 392 */
+ { 32, 21, 12, 0, 0, 32, 0, }, /* 393 */
+ { 32, 6, 12, 0, 0, 32, 0, }, /* 394 */
+ { 32, 23, 12, 0, 0, 32, 0, }, /* 395 */
+ { 32, 13, 12, 0, 0, 32, 0, }, /* 396 */
+ { 32, 15, 12, 0, 0, 32, 0, }, /* 397 */
+ { 38, 21, 12, 0, 0, 38, 0, }, /* 398 */
+ { 10, 21, 12, 0, 0, -79, 0, }, /* 399 */
+ { 38, 17, 12, 0, 0, 38, 0, }, /* 400 */
+ { 38, 12, 3, 0, 0, 38, 0, }, /* 401 */
+ { 38, 1, 2, 0, 0, 38, 0, }, /* 402 */
+ { 38, 13, 12, 0, 0, 38, 0, }, /* 403 */
+ { 38, 7, 12, 0, 0, 38, 0, }, /* 404 */
+ { 38, 6, 12, 0, 0, 38, 0, }, /* 405 */
+ { 35, 7, 12, 0, 0, 35, 0, }, /* 406 */
+ { 35, 12, 3, 0, 0, 35, 0, }, /* 407 */
+ { 35, 10, 5, 0, 0, 35, 0, }, /* 408 */
+ { 35, 26, 12, 0, 0, 35, 0, }, /* 409 */
+ { 35, 21, 12, 0, 0, 35, 0, }, /* 410 */
+ { 35, 13, 12, 0, 0, 35, 0, }, /* 411 */
+ { 53, 7, 12, 0, 0, 53, 0, }, /* 412 */
+ { 40, 7, 12, 0, 0, 40, 0, }, /* 413 */
+ { 40, 13, 12, 0, 0, 40, 0, }, /* 414 */
+ { 40, 15, 12, 0, 0, 40, 0, }, /* 415 */
+ { 40, 26, 12, 0, 0, 40, 0, }, /* 416 */
+ { 32, 26, 12, 0, 0, 32, 0, }, /* 417 */
+ { 6, 7, 12, 0, 0, 6, 0, }, /* 418 */
+ { 6, 12, 3, 0, 0, 6, 0, }, /* 419 */
+ { 6, 10, 5, 0, 0, 6, 0, }, /* 420 */
+ { 6, 21, 12, 0, 0, 6, 0, }, /* 421 */
+ { 91, 7, 12, 0, 0, 91, 0, }, /* 422 */
+ { 91, 10, 5, 0, 0, 91, 0, }, /* 423 */
+ { 91, 12, 3, 0, 0, 91, 0, }, /* 424 */
+ { 91, 10, 12, 0, 0, 91, 0, }, /* 425 */
+ { 91, 13, 12, 0, 0, 91, 0, }, /* 426 */
+ { 91, 21, 12, 0, 0, 91, 0, }, /* 427 */
+ { 91, 6, 12, 0, 0, 91, 0, }, /* 428 */
+ { 28, 11, 3, 0, 0, 28, 0, }, /* 429 */
+ { 62, 12, 3, 0, 0, 62, 0, }, /* 430 */
+ { 62, 10, 5, 0, 0, 62, 0, }, /* 431 */
+ { 62, 7, 12, 0, 0, 62, 0, }, /* 432 */
+ { 62, 10, 3, 0, 0, 62, 0, }, /* 433 */
+ { 62, 13, 12, 0, 0, 62, 0, }, /* 434 */
+ { 62, 21, 12, 0, 0, 62, 0, }, /* 435 */
+ { 62, 26, 12, 0, 0, 62, 0, }, /* 436 */
+ { 76, 12, 3, 0, 0, 76, 0, }, /* 437 */
+ { 76, 10, 5, 0, 0, 76, 0, }, /* 438 */
+ { 76, 7, 12, 0, 0, 76, 0, }, /* 439 */
+ { 76, 13, 12, 0, 0, 76, 0, }, /* 440 */
+ { 93, 7, 12, 0, 0, 93, 0, }, /* 441 */
+ { 93, 12, 3, 0, 0, 93, 0, }, /* 442 */
+ { 93, 10, 5, 0, 0, 93, 0, }, /* 443 */
+ { 93, 21, 12, 0, 0, 93, 0, }, /* 444 */
+ { 70, 7, 12, 0, 0, 70, 0, }, /* 445 */
+ { 70, 10, 5, 0, 0, 70, 0, }, /* 446 */
+ { 70, 12, 3, 0, 0, 70, 0, }, /* 447 */
+ { 70, 21, 12, 0, 0, 70, 0, }, /* 448 */
+ { 70, 13, 12, 0, 0, 70, 0, }, /* 449 */
+ { 73, 13, 12, 0, 0, 73, 0, }, /* 450 */
+ { 73, 7, 12, 0, 0, 73, 0, }, /* 451 */
+ { 73, 6, 12, 0, 0, 73, 0, }, /* 452 */
+ { 73, 21, 12, 0, 0, 73, 0, }, /* 453 */
+ { 13, 5, 12, 63, -6222, 13, 0, }, /* 454 */
+ { 13, 5, 12, 67, -6221, 13, 0, }, /* 455 */
+ { 13, 5, 12, 71, -6212, 13, 0, }, /* 456 */
+ { 13, 5, 12, 75, -6210, 13, 0, }, /* 457 */
+ { 13, 5, 12, 79, -6210, 13, 0, }, /* 458 */
+ { 13, 5, 12, 79, -6211, 13, 0, }, /* 459 */
+ { 13, 5, 12, 84, -6204, 13, 0, }, /* 460 */
+ { 13, 5, 12, 88, -6180, 13, 0, }, /* 461 */
+ { 13, 5, 12, 108, 35267, 13, 0, }, /* 462 */
+ { 17, 9, 12, 0, -3008, 17, 0, }, /* 463 */
+ { 76, 21, 12, 0, 0, 76, 0, }, /* 464 */
+ { 28, 12, 3, 0, 0, -122, 0, }, /* 465 */
+ { 28, 12, 3, 0, 0, 15, 0, }, /* 466 */
+ { 10, 21, 12, 0, 0, -40, 0, }, /* 467 */
+ { 28, 12, 3, 0, 0, -16, 0, }, /* 468 */
+ { 28, 12, 3, 0, 0, -46, 0, }, /* 469 */
+ { 28, 12, 3, 0, 0, -157, 0, }, /* 470 */
+ { 10, 10, 5, 0, 0, -16, 0, }, /* 471 */
+ { 10, 7, 12, 0, 0, -43, 0, }, /* 472 */
+ { 10, 7, 12, 0, 0, -16, 0, }, /* 473 */
+ { 10, 7, 12, 0, 0, 15, 0, }, /* 474 */
+ { 10, 7, 12, 0, 0, -172, 0, }, /* 475 */
+ { 10, 7, 12, 0, 0, -40, 0, }, /* 476 */
+ { 28, 12, 3, 0, 0, -106, 0, }, /* 477 */
+ { 10, 10, 5, 0, 0, 3, 0, }, /* 478 */
+ { 28, 12, 3, 0, 0, -40, 0, }, /* 479 */
+ { 10, 7, 12, 0, 0, 150, 0, }, /* 480 */
+ { 13, 5, 12, 0, 0, 13, 0, }, /* 481 */
+ { 13, 6, 12, 0, 0, 13, 0, }, /* 482 */
+ { 34, 5, 12, 0, 35332, 34, 0, }, /* 483 */
+ { 34, 5, 12, 0, 3814, 34, 0, }, /* 484 */
+ { 34, 5, 12, 0, 35384, 34, 0, }, /* 485 */
+ { 28, 12, 3, 0, 0, -37, 0, }, /* 486 */
+ { 28, 12, 3, 0, 0, 50, 0, }, /* 487 */
+ { 34, 9, 12, 92, 1, 34, 0, }, /* 488 */
+ { 34, 5, 12, 92, -1, 34, 0, }, /* 489 */
+ { 34, 5, 12, 92, -58, 34, 0, }, /* 490 */
+ { 34, 9, 12, 0, -7615, 34, 0, }, /* 491 */
+ { 20, 5, 12, 0, 8, 20, 0, }, /* 492 */
+ { 20, 9, 12, 0, -8, 20, 0, }, /* 493 */
+ { 20, 5, 12, 0, 74, 20, 0, }, /* 494 */
+ { 20, 5, 12, 0, 86, 20, 0, }, /* 495 */
+ { 20, 5, 12, 0, 100, 20, 0, }, /* 496 */
+ { 20, 5, 12, 0, 128, 20, 0, }, /* 497 */
+ { 20, 5, 12, 0, 112, 20, 0, }, /* 498 */
+ { 20, 5, 12, 0, 126, 20, 0, }, /* 499 */
+ { 20, 8, 12, 0, -8, 20, 0, }, /* 500 */
+ { 20, 5, 12, 0, 9, 20, 0, }, /* 501 */
+ { 20, 9, 12, 0, -74, 20, 0, }, /* 502 */
+ { 20, 8, 12, 0, -9, 20, 0, }, /* 503 */
+ { 20, 5, 12, 21, -7173, 20, 0, }, /* 504 */
+ { 20, 9, 12, 0, -86, 20, 0, }, /* 505 */
+ { 20, 9, 12, 0, -100, 20, 0, }, /* 506 */
+ { 20, 9, 12, 0, -112, 20, 0, }, /* 507 */
+ { 20, 9, 12, 0, -128, 20, 0, }, /* 508 */
+ { 20, 9, 12, 0, -126, 20, 0, }, /* 509 */
+ { 28, 1, 3, 0, 0, 28, 0, }, /* 510 */
+ { 28, 1, 13, 0, 0, 28, 0, }, /* 511 */
+ { 10, 27, 2, 0, 0, 10, 0, }, /* 512 */
+ { 10, 28, 2, 0, 0, 10, 0, }, /* 513 */
+ { 10, 29, 12, 0, 0, -73, 0, }, /* 514 */
+ { 10, 21, 14, 0, 0, 10, 0, }, /* 515 */
+ { 0, 2, 2, 0, 0, 0, 0, }, /* 516 */
+ { 28, 12, 3, 0, 0, -110, 0, }, /* 517 */
+ { 10, 9, 12, 0, 0, 10, 0, }, /* 518 */
+ { 10, 5, 12, 0, 0, 10, 0, }, /* 519 */
+ { 20, 9, 12, 96, -7517, 20, 0, }, /* 520 */
+ { 34, 9, 12, 100, -8383, 34, 0, }, /* 521 */
+ { 34, 9, 12, 104, -8262, 34, 0, }, /* 522 */
+ { 34, 9, 12, 0, 28, 34, 0, }, /* 523 */
+ { 10, 7, 12, 0, 0, 10, 0, }, /* 524 */
+ { 10, 5, 14, 0, 0, 10, 0, }, /* 525 */
+ { 34, 5, 12, 0, -28, 34, 0, }, /* 526 */
+ { 34, 14, 12, 0, 16, 34, 0, }, /* 527 */
+ { 34, 14, 12, 0, -16, 34, 0, }, /* 528 */
+ { 34, 14, 12, 0, 0, 34, 0, }, /* 529 */
+ { 10, 25, 14, 0, 0, 10, 0, }, /* 530 */
+ { 10, 26, 12, 0, 26, 10, 0, }, /* 531 */
+ { 10, 26, 14, 0, 26, 10, 0, }, /* 532 */
+ { 10, 26, 12, 0, -26, 10, 0, }, /* 533 */
+ { 5, 26, 12, 0, 0, 5, 0, }, /* 534 */
+ { 18, 9, 12, 0, 48, 18, 0, }, /* 535 */
+ { 18, 5, 12, 0, -48, 18, 0, }, /* 536 */
+ { 34, 9, 12, 0, -10743, 34, 0, }, /* 537 */
+ { 34, 9, 12, 0, -3814, 34, 0, }, /* 538 */
+ { 34, 9, 12, 0, -10727, 34, 0, }, /* 539 */
+ { 34, 5, 12, 0, -10795, 34, 0, }, /* 540 */
+ { 34, 5, 12, 0, -10792, 34, 0, }, /* 541 */
+ { 34, 9, 12, 0, -10780, 34, 0, }, /* 542 */
+ { 34, 9, 12, 0, -10749, 34, 0, }, /* 543 */
+ { 34, 9, 12, 0, -10783, 34, 0, }, /* 544 */
+ { 34, 9, 12, 0, -10782, 34, 0, }, /* 545 */
+ { 34, 9, 12, 0, -10815, 34, 0, }, /* 546 */
+ { 11, 5, 12, 0, 0, 11, 0, }, /* 547 */
+ { 11, 26, 12, 0, 0, 11, 0, }, /* 548 */
+ { 11, 12, 3, 0, 0, 11, 0, }, /* 549 */
+ { 11, 21, 12, 0, 0, 11, 0, }, /* 550 */
+ { 11, 15, 12, 0, 0, 11, 0, }, /* 551 */
+ { 17, 5, 12, 0, -7264, 17, 0, }, /* 552 */
+ { 59, 7, 12, 0, 0, 59, 0, }, /* 553 */
+ { 59, 6, 12, 0, 0, 59, 0, }, /* 554 */
+ { 59, 21, 12, 0, 0, 59, 0, }, /* 555 */
+ { 59, 12, 3, 0, 0, 59, 0, }, /* 556 */
+ { 13, 12, 3, 0, 0, 13, 0, }, /* 557 */
+ { 10, 21, 12, 0, 0, -28, 0, }, /* 558 */
+ { 23, 26, 12, 0, 0, 23, 0, }, /* 559 */
+ { 10, 21, 12, 0, 0, -150, 0, }, /* 560 */
+ { 10, 21, 12, 0, 0, -137, 0, }, /* 561 */
+ { 23, 6, 12, 0, 0, 23, 0, }, /* 562 */
+ { 10, 7, 12, 0, 0, 23, 0, }, /* 563 */
+ { 23, 14, 12, 0, 0, 23, 0, }, /* 564 */
+ { 10, 22, 12, 0, 0, -150, 0, }, /* 565 */
+ { 10, 18, 12, 0, 0, -150, 0, }, /* 566 */
+ { 10, 26, 12, 0, 0, -137, 0, }, /* 567 */
+ { 10, 17, 12, 0, 0, -137, 0, }, /* 568 */
+ { 10, 22, 12, 0, 0, -137, 0, }, /* 569 */
+ { 10, 18, 12, 0, 0, -137, 0, }, /* 570 */
+ { 28, 12, 3, 0, 0, -19, 0, }, /* 571 */
+ { 24, 10, 3, 0, 0, 24, 0, }, /* 572 */
+ { 10, 17, 14, 0, 0, -137, 0, }, /* 573 */
+ { 10, 6, 12, 0, 0, -67, 0, }, /* 574 */
+ { 10, 7, 12, 0, 0, -114, 0, }, /* 575 */
+ { 10, 21, 14, 0, 0, -114, 0, }, /* 576 */
+ { 10, 26, 12, 0, 0, 23, 0, }, /* 577 */
+ { 27, 7, 12, 0, 0, 27, 0, }, /* 578 */
+ { 28, 12, 3, 0, 0, -67, 0, }, /* 579 */
+ { 10, 24, 12, 0, 0, -67, 0, }, /* 580 */
+ { 27, 6, 12, 0, 0, 27, 0, }, /* 581 */
+ { 10, 17, 12, 0, 0, -67, 0, }, /* 582 */
+ { 30, 7, 12, 0, 0, 30, 0, }, /* 583 */
+ { 30, 6, 12, 0, 0, 30, 0, }, /* 584 */
+ { 4, 7, 12, 0, 0, 4, 0, }, /* 585 */
+ { 24, 7, 12, 0, 0, 24, 0, }, /* 586 */
+ { 10, 15, 12, 0, 0, 23, 0, }, /* 587 */
+ { 24, 26, 12, 0, 0, 24, 0, }, /* 588 */
+ { 10, 26, 14, 0, 0, 23, 0, }, /* 589 */
+ { 30, 26, 12, 0, 0, 30, 0, }, /* 590 */
+ { 23, 7, 12, 0, 0, 23, 0, }, /* 591 */
+ { 61, 7, 12, 0, 0, 61, 0, }, /* 592 */
+ { 61, 6, 12, 0, 0, 61, 0, }, /* 593 */
+ { 61, 26, 12, 0, 0, 61, 0, }, /* 594 */
+ { 86, 7, 12, 0, 0, 86, 0, }, /* 595 */
+ { 86, 6, 12, 0, 0, 86, 0, }, /* 596 */
+ { 86, 21, 12, 0, 0, 86, 0, }, /* 597 */
+ { 77, 7, 12, 0, 0, 77, 0, }, /* 598 */
+ { 77, 6, 12, 0, 0, 77, 0, }, /* 599 */
+ { 77, 21, 12, 0, 0, 77, 0, }, /* 600 */
+ { 77, 13, 12, 0, 0, 77, 0, }, /* 601 */
+ { 13, 9, 12, 108, 1, 13, 0, }, /* 602 */
+ { 13, 5, 12, 108, -35267, 13, 0, }, /* 603 */
+ { 13, 7, 12, 0, 0, 13, 0, }, /* 604 */
+ { 13, 21, 12, 0, 0, 13, 0, }, /* 605 */
+ { 79, 7, 12, 0, 0, 79, 0, }, /* 606 */
+ { 79, 14, 12, 0, 0, 79, 0, }, /* 607 */
+ { 79, 12, 3, 0, 0, 79, 0, }, /* 608 */
+ { 79, 21, 12, 0, 0, 79, 0, }, /* 609 */
+ { 10, 24, 12, 0, 0, -64, 0, }, /* 610 */
+ { 34, 9, 12, 0, -35332, 34, 0, }, /* 611 */
+ { 34, 9, 12, 0, -42280, 34, 0, }, /* 612 */
+ { 34, 5, 12, 0, 48, 34, 0, }, /* 613 */
+ { 34, 9, 12, 0, -42308, 34, 0, }, /* 614 */
+ { 34, 9, 12, 0, -42319, 34, 0, }, /* 615 */
+ { 34, 9, 12, 0, -42315, 34, 0, }, /* 616 */
+ { 34, 9, 12, 0, -42305, 34, 0, }, /* 617 */
+ { 34, 9, 12, 0, -42258, 34, 0, }, /* 618 */
+ { 34, 9, 12, 0, -42282, 34, 0, }, /* 619 */
+ { 34, 9, 12, 0, -42261, 34, 0, }, /* 620 */
+ { 34, 9, 12, 0, 928, 34, 0, }, /* 621 */
+ { 34, 9, 12, 0, -48, 34, 0, }, /* 622 */
+ { 34, 9, 12, 0, -42307, 34, 0, }, /* 623 */
+ { 34, 9, 12, 0, -35384, 34, 0, }, /* 624 */
+ { 49, 7, 12, 0, 0, 49, 0, }, /* 625 */
+ { 49, 12, 3, 0, 0, 49, 0, }, /* 626 */
+ { 49, 10, 5, 0, 0, 49, 0, }, /* 627 */
+ { 49, 26, 12, 0, 0, 49, 0, }, /* 628 */
+ { 10, 15, 12, 0, 0, -244, 0, }, /* 629 */
+ { 10, 15, 12, 0, 0, -230, 0, }, /* 630 */
+ { 10, 26, 12, 0, 0, -191, 0, }, /* 631 */
+ { 10, 23, 12, 0, 0, -191, 0, }, /* 632 */
+ { 65, 7, 12, 0, 0, 65, 0, }, /* 633 */
+ { 65, 21, 12, 0, 0, 65, 0, }, /* 634 */
+ { 75, 10, 5, 0, 0, 75, 0, }, /* 635 */
+ { 75, 7, 12, 0, 0, 75, 0, }, /* 636 */
+ { 75, 12, 3, 0, 0, 75, 0, }, /* 637 */
+ { 75, 21, 12, 0, 0, 75, 0, }, /* 638 */
+ { 75, 13, 12, 0, 0, 75, 0, }, /* 639 */
+ { 15, 12, 3, 0, 0, -16, 0, }, /* 640 */
+ { 15, 7, 12, 0, 0, -49, 0, }, /* 641 */
+ { 69, 13, 12, 0, 0, 69, 0, }, /* 642 */
+ { 69, 7, 12, 0, 0, 69, 0, }, /* 643 */
+ { 69, 12, 3, 0, 0, 69, 0, }, /* 644 */
+ { 10, 21, 12, 0, 0, -118, 0, }, /* 645 */
+ { 69, 21, 12, 0, 0, 69, 0, }, /* 646 */
+ { 74, 7, 12, 0, 0, 74, 0, }, /* 647 */
+ { 74, 12, 3, 0, 0, 74, 0, }, /* 648 */
+ { 74, 10, 5, 0, 0, 74, 0, }, /* 649 */
+ { 74, 21, 12, 0, 0, 74, 0, }, /* 650 */
+ { 84, 12, 3, 0, 0, 84, 0, }, /* 651 */
+ { 84, 10, 5, 0, 0, 84, 0, }, /* 652 */
+ { 84, 7, 12, 0, 0, 84, 0, }, /* 653 */
+ { 84, 21, 12, 0, 0, 84, 0, }, /* 654 */
+ { 10, 6, 12, 0, 0, -22, 0, }, /* 655 */
+ { 84, 13, 12, 0, 0, 84, 0, }, /* 656 */
+ { 39, 6, 12, 0, 0, 39, 0, }, /* 657 */
+ { 68, 7, 12, 0, 0, 68, 0, }, /* 658 */
+ { 68, 12, 3, 0, 0, 68, 0, }, /* 659 */
+ { 68, 10, 5, 0, 0, 68, 0, }, /* 660 */
+ { 68, 13, 12, 0, 0, 68, 0, }, /* 661 */
+ { 68, 21, 12, 0, 0, 68, 0, }, /* 662 */
+ { 92, 7, 12, 0, 0, 92, 0, }, /* 663 */
+ { 92, 12, 3, 0, 0, 92, 0, }, /* 664 */
+ { 92, 6, 12, 0, 0, 92, 0, }, /* 665 */
+ { 92, 21, 12, 0, 0, 92, 0, }, /* 666 */
+ { 87, 7, 12, 0, 0, 87, 0, }, /* 667 */
+ { 87, 10, 5, 0, 0, 87, 0, }, /* 668 */
+ { 87, 12, 3, 0, 0, 87, 0, }, /* 669 */
+ { 87, 21, 12, 0, 0, 87, 0, }, /* 670 */
+ { 87, 6, 12, 0, 0, 87, 0, }, /* 671 */
+ { 34, 5, 12, 0, -928, 34, 0, }, /* 672 */
+ { 9, 5, 12, 0, -38864, 9, 0, }, /* 673 */
+ { 87, 13, 12, 0, 0, 87, 0, }, /* 674 */
+ { 24, 7, 9, 0, 0, 24, 0, }, /* 675 */
+ { 24, 7, 10, 0, 0, 24, 0, }, /* 676 */
+ { 0, 4, 12, 0, 0, 0, 0, }, /* 677 */
+ { 0, 3, 12, 0, 0, 0, 0, }, /* 678 */
+ { 26, 25, 12, 0, 0, 26, 0, }, /* 679 */
+ { 10, 18, 12, 0, 0, -7, 0, }, /* 680 */
+ { 10, 22, 12, 0, 0, -7, 0, }, /* 681 */
+ { 1, 7, 12, 0, 0, -13, 0, }, /* 682 */
+ { 1, 26, 12, 0, 0, -13, 0, }, /* 683 */
+ { 10, 6, 3, 0, 0, -67, 0, }, /* 684 */
+ { 36, 7, 12, 0, 0, 36, 0, }, /* 685 */
+ { 10, 21, 12, 0, 0, -98, 0, }, /* 686 */
+ { 10, 21, 12, 0, 0, -25, 0, }, /* 687 */
+ { 10, 15, 12, 0, 0, -102, 0, }, /* 688 */
+ { 10, 26, 12, 0, 0, -25, 0, }, /* 689 */
+ { 20, 14, 12, 0, 0, 20, 0, }, /* 690 */
+ { 20, 15, 12, 0, 0, 20, 0, }, /* 691 */
+ { 20, 26, 12, 0, 0, 20, 0, }, /* 692 */
+ { 71, 7, 12, 0, 0, 71, 0, }, /* 693 */
+ { 67, 7, 12, 0, 0, 67, 0, }, /* 694 */
+ { 28, 12, 3, 0, 0, -1, 0, }, /* 695 */
+ { 10, 15, 12, 0, 0, -1, 0, }, /* 696 */
+ { 42, 7, 12, 0, 0, 42, 0, }, /* 697 */
+ { 42, 15, 12, 0, 0, 42, 0, }, /* 698 */
+ { 19, 7, 12, 0, 0, 19, 0, }, /* 699 */
+ { 19, 14, 12, 0, 0, 19, 0, }, /* 700 */
+ { 118, 7, 12, 0, 0, 118, 0, }, /* 701 */
+ { 118, 12, 3, 0, 0, 118, 0, }, /* 702 */
+ { 60, 7, 12, 0, 0, 60, 0, }, /* 703 */
+ { 60, 21, 12, 0, 0, 60, 0, }, /* 704 */
+ { 43, 7, 12, 0, 0, 43, 0, }, /* 705 */
+ { 43, 21, 12, 0, 0, 43, 0, }, /* 706 */
+ { 43, 14, 12, 0, 0, 43, 0, }, /* 707 */
+ { 14, 9, 12, 0, 40, 14, 0, }, /* 708 */
+ { 14, 5, 12, 0, -40, 14, 0, }, /* 709 */
+ { 47, 7, 12, 0, 0, 47, 0, }, /* 710 */
+ { 45, 7, 12, 0, 0, 45, 0, }, /* 711 */
+ { 45, 13, 12, 0, 0, 45, 0, }, /* 712 */
+ { 136, 9, 12, 0, 40, 136, 0, }, /* 713 */
+ { 136, 5, 12, 0, -40, 136, 0, }, /* 714 */
+ { 106, 7, 12, 0, 0, 106, 0, }, /* 715 */
+ { 104, 7, 12, 0, 0, 104, 0, }, /* 716 */
+ { 104, 21, 12, 0, 0, 104, 0, }, /* 717 */
+ { 161, 9, 12, 0, 39, 161, 0, }, /* 718 */
+ { 161, 5, 12, 0, -39, 161, 0, }, /* 719 */
+ { 110, 7, 12, 0, 0, 110, 0, }, /* 720 */
+ { 12, 7, 12, 0, 0, 12, 0, }, /* 721 */
+ { 81, 7, 12, 0, 0, 81, 0, }, /* 722 */
+ { 81, 21, 12, 0, 0, 81, 0, }, /* 723 */
+ { 81, 15, 12, 0, 0, 81, 0, }, /* 724 */
+ { 120, 7, 12, 0, 0, 120, 0, }, /* 725 */
+ { 120, 26, 12, 0, 0, 120, 0, }, /* 726 */
+ { 120, 15, 12, 0, 0, 120, 0, }, /* 727 */
+ { 116, 7, 12, 0, 0, 116, 0, }, /* 728 */
+ { 116, 15, 12, 0, 0, 116, 0, }, /* 729 */
+ { 128, 7, 12, 0, 0, 128, 0, }, /* 730 */
+ { 128, 15, 12, 0, 0, 128, 0, }, /* 731 */
+ { 66, 7, 12, 0, 0, 66, 0, }, /* 732 */
+ { 66, 15, 12, 0, 0, 66, 0, }, /* 733 */
+ { 66, 21, 12, 0, 0, 66, 0, }, /* 734 */
+ { 72, 7, 12, 0, 0, 72, 0, }, /* 735 */
+ { 72, 21, 12, 0, 0, 72, 0, }, /* 736 */
+ { 98, 7, 12, 0, 0, 98, 0, }, /* 737 */
+ { 97, 7, 12, 0, 0, 97, 0, }, /* 738 */
+ { 97, 15, 12, 0, 0, 97, 0, }, /* 739 */
+ { 31, 7, 12, 0, 0, 31, 0, }, /* 740 */
+ { 31, 12, 3, 0, 0, 31, 0, }, /* 741 */
+ { 31, 15, 12, 0, 0, 31, 0, }, /* 742 */
+ { 31, 21, 12, 0, 0, 31, 0, }, /* 743 */
+ { 88, 7, 12, 0, 0, 88, 0, }, /* 744 */
+ { 88, 15, 12, 0, 0, 88, 0, }, /* 745 */
+ { 88, 21, 12, 0, 0, 88, 0, }, /* 746 */
+ { 117, 7, 12, 0, 0, 117, 0, }, /* 747 */
+ { 117, 15, 12, 0, 0, 117, 0, }, /* 748 */
+ { 112, 7, 12, 0, 0, 112, 0, }, /* 749 */
+ { 112, 26, 12, 0, 0, 112, 0, }, /* 750 */
+ { 112, 12, 3, 0, 0, 112, 0, }, /* 751 */
+ { 112, 15, 12, 0, 0, 112, 0, }, /* 752 */
+ { 112, 21, 12, 0, 0, 112, 0, }, /* 753 */
+ { 112, 21, 12, 0, 0, -76, 0, }, /* 754 */
+ { 78, 7, 12, 0, 0, 78, 0, }, /* 755 */
+ { 78, 21, 12, 0, 0, 78, 0, }, /* 756 */
+ { 83, 7, 12, 0, 0, 83, 0, }, /* 757 */
+ { 83, 15, 12, 0, 0, 83, 0, }, /* 758 */
+ { 82, 7, 12, 0, 0, 82, 0, }, /* 759 */
+ { 82, 15, 12, 0, 0, 82, 0, }, /* 760 */
+ { 121, 7, 12, 0, 0, 121, 0, }, /* 761 */
+ { 121, 21, 12, 0, 0, 121, 0, }, /* 762 */
+ { 121, 15, 12, 0, 0, 121, 0, }, /* 763 */
+ { 89, 7, 12, 0, 0, 89, 0, }, /* 764 */
+ { 130, 9, 12, 0, 64, 130, 0, }, /* 765 */
+ { 130, 5, 12, 0, -64, 130, 0, }, /* 766 */
+ { 130, 15, 12, 0, 0, 130, 0, }, /* 767 */
+ { 144, 7, 12, 0, 0, 144, 0, }, /* 768 */
+ { 144, 12, 3, 0, 0, 144, 0, }, /* 769 */
+ { 144, 13, 12, 0, 0, 144, 0, }, /* 770 */
+ { 1, 15, 12, 0, 0, 1, 0, }, /* 771 */
+ { 156, 7, 12, 0, 0, 156, 0, }, /* 772 */
+ { 156, 12, 3, 0, 0, 156, 0, }, /* 773 */
+ { 156, 17, 12, 0, 0, 156, 0, }, /* 774 */
+ { 147, 7, 12, 0, 0, 147, 0, }, /* 775 */
+ { 147, 15, 12, 0, 0, 147, 0, }, /* 776 */
+ { 148, 7, 12, 0, 0, 148, 0, }, /* 777 */
+ { 148, 12, 3, 0, 0, 148, 0, }, /* 778 */
+ { 148, 15, 12, 0, 0, 148, 0, }, /* 779 */
+ { 148, 21, 12, 0, 0, 148, 0, }, /* 780 */
+ { 158, 7, 12, 0, 0, 158, 0, }, /* 781 */
+ { 158, 12, 3, 0, 0, 158, 0, }, /* 782 */
+ { 158, 21, 12, 0, 0, 158, 0, }, /* 783 */
+ { 153, 7, 12, 0, 0, 153, 0, }, /* 784 */
+ { 153, 15, 12, 0, 0, 153, 0, }, /* 785 */
+ { 149, 7, 12, 0, 0, 149, 0, }, /* 786 */
+ { 94, 10, 5, 0, 0, 94, 0, }, /* 787 */
+ { 94, 12, 3, 0, 0, 94, 0, }, /* 788 */
+ { 94, 7, 12, 0, 0, 94, 0, }, /* 789 */
+ { 94, 21, 12, 0, 0, 94, 0, }, /* 790 */
+ { 94, 15, 12, 0, 0, 94, 0, }, /* 791 */
+ { 94, 13, 12, 0, 0, 94, 0, }, /* 792 */
+ { 85, 12, 3, 0, 0, 85, 0, }, /* 793 */
+ { 85, 10, 5, 0, 0, 85, 0, }, /* 794 */
+ { 85, 7, 12, 0, 0, 85, 0, }, /* 795 */
+ { 85, 21, 12, 0, 0, 85, 0, }, /* 796 */
+ { 85, 1, 4, 0, 0, 85, 0, }, /* 797 */
+ { 101, 7, 12, 0, 0, 101, 0, }, /* 798 */
+ { 101, 13, 12, 0, 0, 101, 0, }, /* 799 */
+ { 96, 12, 3, 0, 0, 96, 0, }, /* 800 */
+ { 96, 7, 12, 0, 0, 96, 0, }, /* 801 */
+ { 96, 10, 5, 0, 0, 96, 0, }, /* 802 */
+ { 96, 13, 12, 0, 0, 96, 0, }, /* 803 */
+ { 96, 21, 12, 0, 0, 96, 0, }, /* 804 */
+ { 111, 7, 12, 0, 0, 111, 0, }, /* 805 */
+ { 111, 12, 3, 0, 0, 111, 0, }, /* 806 */
+ { 111, 21, 12, 0, 0, 111, 0, }, /* 807 */
+ { 100, 12, 3, 0, 0, 100, 0, }, /* 808 */
+ { 100, 10, 5, 0, 0, 100, 0, }, /* 809 */
+ { 100, 7, 12, 0, 0, 100, 0, }, /* 810 */
+ { 100, 7, 4, 0, 0, 100, 0, }, /* 811 */
+ { 100, 21, 12, 0, 0, 100, 0, }, /* 812 */
+ { 100, 13, 12, 0, 0, 100, 0, }, /* 813 */
+ { 48, 15, 12, 0, 0, 48, 0, }, /* 814 */
+ { 108, 7, 12, 0, 0, 108, 0, }, /* 815 */
+ { 108, 10, 5, 0, 0, 108, 0, }, /* 816 */
+ { 108, 12, 3, 0, 0, 108, 0, }, /* 817 */
+ { 108, 21, 12, 0, 0, 108, 0, }, /* 818 */
+ { 129, 7, 12, 0, 0, 129, 0, }, /* 819 */
+ { 129, 21, 12, 0, 0, 129, 0, }, /* 820 */
+ { 109, 7, 12, 0, 0, 109, 0, }, /* 821 */
+ { 109, 12, 3, 0, 0, 109, 0, }, /* 822 */
+ { 109, 10, 5, 0, 0, 109, 0, }, /* 823 */
+ { 109, 13, 12, 0, 0, 109, 0, }, /* 824 */
+ { 107, 12, 3, 0, 0, 107, 0, }, /* 825 */
+ { 107, 12, 3, 0, 0, -55, 0, }, /* 826 */
+ { 107, 10, 5, 0, 0, 107, 0, }, /* 827 */
+ { 107, 10, 5, 0, 0, -55, 0, }, /* 828 */
+ { 107, 7, 12, 0, 0, 107, 0, }, /* 829 */
+ { 28, 12, 3, 0, 0, -55, 0, }, /* 830 */
+ { 107, 10, 3, 0, 0, 107, 0, }, /* 831 */
+ { 135, 7, 12, 0, 0, 135, 0, }, /* 832 */
+ { 135, 10, 5, 0, 0, 135, 0, }, /* 833 */
+ { 135, 12, 3, 0, 0, 135, 0, }, /* 834 */
+ { 135, 21, 12, 0, 0, 135, 0, }, /* 835 */
+ { 135, 13, 12, 0, 0, 135, 0, }, /* 836 */
+ { 124, 7, 12, 0, 0, 124, 0, }, /* 837 */
+ { 124, 10, 3, 0, 0, 124, 0, }, /* 838 */
+ { 124, 10, 5, 0, 0, 124, 0, }, /* 839 */
+ { 124, 12, 3, 0, 0, 124, 0, }, /* 840 */
+ { 124, 21, 12, 0, 0, 124, 0, }, /* 841 */
+ { 124, 13, 12, 0, 0, 124, 0, }, /* 842 */
+ { 123, 7, 12, 0, 0, 123, 0, }, /* 843 */
+ { 123, 10, 3, 0, 0, 123, 0, }, /* 844 */
+ { 123, 10, 5, 0, 0, 123, 0, }, /* 845 */
+ { 123, 12, 3, 0, 0, 123, 0, }, /* 846 */
+ { 123, 21, 12, 0, 0, 123, 0, }, /* 847 */
+ { 114, 7, 12, 0, 0, 114, 0, }, /* 848 */
+ { 114, 10, 5, 0, 0, 114, 0, }, /* 849 */
+ { 114, 12, 3, 0, 0, 114, 0, }, /* 850 */
+ { 114, 21, 12, 0, 0, 114, 0, }, /* 851 */
+ { 114, 13, 12, 0, 0, 114, 0, }, /* 852 */
+ { 102, 7, 12, 0, 0, 102, 0, }, /* 853 */
+ { 102, 12, 3, 0, 0, 102, 0, }, /* 854 */
+ { 102, 10, 5, 0, 0, 102, 0, }, /* 855 */
+ { 102, 21, 12, 0, 0, 102, 0, }, /* 856 */
+ { 102, 13, 12, 0, 0, 102, 0, }, /* 857 */
+ { 126, 7, 12, 0, 0, 126, 0, }, /* 858 */
+ { 126, 12, 3, 0, 0, 126, 0, }, /* 859 */
+ { 126, 10, 12, 0, 0, 126, 0, }, /* 860 */
+ { 126, 10, 5, 0, 0, 126, 0, }, /* 861 */
+ { 126, 13, 12, 0, 0, 126, 0, }, /* 862 */
+ { 126, 15, 12, 0, 0, 126, 0, }, /* 863 */
+ { 126, 21, 12, 0, 0, 126, 0, }, /* 864 */
+ { 126, 26, 12, 0, 0, 126, 0, }, /* 865 */
+ { 142, 7, 12, 0, 0, 142, 0, }, /* 866 */
+ { 142, 10, 5, 0, 0, 142, 0, }, /* 867 */
+ { 142, 12, 3, 0, 0, 142, 0, }, /* 868 */
+ { 142, 21, 12, 0, 0, 142, 0, }, /* 869 */
+ { 125, 9, 12, 0, 32, 125, 0, }, /* 870 */
+ { 125, 5, 12, 0, -32, 125, 0, }, /* 871 */
+ { 125, 13, 12, 0, 0, 125, 0, }, /* 872 */
+ { 125, 15, 12, 0, 0, 125, 0, }, /* 873 */
+ { 125, 7, 12, 0, 0, 125, 0, }, /* 874 */
+ { 154, 7, 12, 0, 0, 154, 0, }, /* 875 */
+ { 154, 10, 3, 0, 0, 154, 0, }, /* 876 */
+ { 154, 10, 5, 0, 0, 154, 0, }, /* 877 */
+ { 154, 12, 3, 0, 0, 154, 0, }, /* 878 */
+ { 154, 7, 4, 0, 0, 154, 0, }, /* 879 */
+ { 154, 21, 12, 0, 0, 154, 0, }, /* 880 */
+ { 154, 13, 12, 0, 0, 154, 0, }, /* 881 */
+ { 150, 7, 12, 0, 0, 150, 0, }, /* 882 */
+ { 150, 10, 5, 0, 0, 150, 0, }, /* 883 */
+ { 150, 12, 3, 0, 0, 150, 0, }, /* 884 */
+ { 150, 21, 12, 0, 0, 150, 0, }, /* 885 */
+ { 141, 7, 12, 0, 0, 141, 0, }, /* 886 */
+ { 141, 12, 3, 0, 0, 141, 0, }, /* 887 */
+ { 141, 10, 5, 0, 0, 141, 0, }, /* 888 */
+ { 141, 7, 4, 0, 0, 141, 0, }, /* 889 */
+ { 141, 21, 12, 0, 0, 141, 0, }, /* 890 */
+ { 140, 7, 12, 0, 0, 140, 0, }, /* 891 */
+ { 140, 12, 3, 0, 0, 140, 0, }, /* 892 */
+ { 140, 10, 5, 0, 0, 140, 0, }, /* 893 */
+ { 140, 7, 4, 0, 0, 140, 0, }, /* 894 */
+ { 140, 21, 12, 0, 0, 140, 0, }, /* 895 */
+ { 122, 7, 12, 0, 0, 122, 0, }, /* 896 */
+ { 133, 7, 12, 0, 0, 133, 0, }, /* 897 */
+ { 133, 10, 5, 0, 0, 133, 0, }, /* 898 */
+ { 133, 12, 3, 0, 0, 133, 0, }, /* 899 */
+ { 133, 21, 12, 0, 0, 133, 0, }, /* 900 */
+ { 133, 13, 12, 0, 0, 133, 0, }, /* 901 */
+ { 133, 15, 12, 0, 0, 133, 0, }, /* 902 */
+ { 134, 21, 12, 0, 0, 134, 0, }, /* 903 */
+ { 134, 7, 12, 0, 0, 134, 0, }, /* 904 */
+ { 134, 12, 3, 0, 0, 134, 0, }, /* 905 */
+ { 134, 10, 5, 0, 0, 134, 0, }, /* 906 */
+ { 138, 7, 12, 0, 0, 138, 0, }, /* 907 */
+ { 138, 12, 3, 0, 0, 138, 0, }, /* 908 */
+ { 138, 7, 4, 0, 0, 138, 0, }, /* 909 */
+ { 138, 13, 12, 0, 0, 138, 0, }, /* 910 */
+ { 143, 7, 12, 0, 0, 143, 0, }, /* 911 */
+ { 143, 10, 5, 0, 0, 143, 0, }, /* 912 */
+ { 143, 12, 3, 0, 0, 143, 0, }, /* 913 */
+ { 143, 13, 12, 0, 0, 143, 0, }, /* 914 */
+ { 145, 7, 12, 0, 0, 145, 0, }, /* 915 */
+ { 145, 12, 3, 0, 0, 145, 0, }, /* 916 */
+ { 145, 10, 5, 0, 0, 145, 0, }, /* 917 */
+ { 145, 21, 12, 0, 0, 145, 0, }, /* 918 */
+ { 54, 15, 12, 0, 0, 54, 0, }, /* 919 */
+ { 54, 21, 12, 0, 0, 54, 0, }, /* 920 */
+ { 63, 7, 12, 0, 0, 63, 0, }, /* 921 */
+ { 63, 14, 12, 0, 0, 63, 0, }, /* 922 */
+ { 63, 21, 12, 0, 0, 63, 0, }, /* 923 */
+ { 157, 7, 12, 0, 0, 157, 0, }, /* 924 */
+ { 157, 21, 12, 0, 0, 157, 0, }, /* 925 */
+ { 80, 7, 12, 0, 0, 80, 0, }, /* 926 */
+ { 80, 1, 2, 0, 0, 80, 0, }, /* 927 */
+ { 127, 7, 12, 0, 0, 127, 0, }, /* 928 */
+ { 115, 7, 12, 0, 0, 115, 0, }, /* 929 */
+ { 115, 13, 12, 0, 0, 115, 0, }, /* 930 */
+ { 115, 21, 12, 0, 0, 115, 0, }, /* 931 */
+ { 159, 7, 12, 0, 0, 159, 0, }, /* 932 */
+ { 159, 13, 12, 0, 0, 159, 0, }, /* 933 */
+ { 103, 7, 12, 0, 0, 103, 0, }, /* 934 */
+ { 103, 12, 3, 0, 0, 103, 0, }, /* 935 */
+ { 103, 21, 12, 0, 0, 103, 0, }, /* 936 */
+ { 119, 7, 12, 0, 0, 119, 0, }, /* 937 */
+ { 119, 12, 3, 0, 0, 119, 0, }, /* 938 */
+ { 119, 21, 12, 0, 0, 119, 0, }, /* 939 */
+ { 119, 26, 12, 0, 0, 119, 0, }, /* 940 */
+ { 119, 6, 12, 0, 0, 119, 0, }, /* 941 */
+ { 119, 13, 12, 0, 0, 119, 0, }, /* 942 */
+ { 119, 15, 12, 0, 0, 119, 0, }, /* 943 */
+ { 146, 9, 12, 0, 32, 146, 0, }, /* 944 */
+ { 146, 5, 12, 0, -32, 146, 0, }, /* 945 */
+ { 146, 15, 12, 0, 0, 146, 0, }, /* 946 */
+ { 146, 21, 12, 0, 0, 146, 0, }, /* 947 */
+ { 99, 7, 12, 0, 0, 99, 0, }, /* 948 */
+ { 99, 12, 3, 0, 0, 99, 0, }, /* 949 */
+ { 99, 10, 5, 0, 0, 99, 0, }, /* 950 */
+ { 99, 6, 12, 0, 0, 99, 0, }, /* 951 */
+ { 137, 6, 12, 0, 0, 137, 0, }, /* 952 */
+ { 139, 6, 12, 0, 0, 139, 0, }, /* 953 */
+ { 23, 21, 12, 0, 0, 23, 0, }, /* 954 */
+ { 155, 12, 3, 0, 0, 155, 0, }, /* 955 */
+ { 23, 10, 5, 0, 0, 23, 0, }, /* 956 */
+ { 137, 7, 12, 0, 0, 137, 0, }, /* 957 */
+ { 155, 7, 12, 0, 0, 155, 0, }, /* 958 */
+ { 139, 7, 12, 0, 0, 139, 0, }, /* 959 */
+ { 105, 7, 12, 0, 0, 105, 0, }, /* 960 */
+ { 105, 26, 12, 0, 0, 105, 0, }, /* 961 */
+ { 105, 12, 3, 0, 0, 105, 0, }, /* 962 */
+ { 105, 21, 12, 0, 0, 105, 0, }, /* 963 */
+ { 10, 1, 2, 0, 0, 105, 0, }, /* 964 */
+ { 10, 10, 3, 0, 0, 10, 0, }, /* 965 */
+ { 10, 10, 5, 0, 0, 10, 0, }, /* 966 */
+ { 20, 12, 3, 0, 0, 20, 0, }, /* 967 */
+ { 131, 26, 12, 0, 0, 131, 0, }, /* 968 */
+ { 131, 12, 3, 0, 0, 131, 0, }, /* 969 */
+ { 131, 21, 12, 0, 0, 131, 0, }, /* 970 */
+ { 18, 12, 3, 0, 0, 18, 0, }, /* 971 */
+ { 151, 7, 12, 0, 0, 151, 0, }, /* 972 */
+ { 151, 12, 3, 0, 0, 151, 0, }, /* 973 */
+ { 151, 6, 12, 0, 0, 151, 0, }, /* 974 */
+ { 151, 13, 12, 0, 0, 151, 0, }, /* 975 */
+ { 151, 26, 12, 0, 0, 151, 0, }, /* 976 */
+ { 160, 7, 12, 0, 0, 160, 0, }, /* 977 */
+ { 160, 12, 3, 0, 0, 160, 0, }, /* 978 */
+ { 152, 7, 12, 0, 0, 152, 0, }, /* 979 */
+ { 152, 12, 3, 0, 0, 152, 0, }, /* 980 */
+ { 152, 13, 12, 0, 0, 152, 0, }, /* 981 */
+ { 152, 23, 12, 0, 0, 152, 0, }, /* 982 */
+ { 113, 7, 12, 0, 0, 113, 0, }, /* 983 */
+ { 113, 15, 12, 0, 0, 113, 0, }, /* 984 */
+ { 113, 12, 3, 0, 0, 113, 0, }, /* 985 */
+ { 132, 9, 12, 0, 34, 132, 0, }, /* 986 */
+ { 132, 5, 12, 0, -34, 132, 0, }, /* 987 */
+ { 132, 12, 3, 0, 0, 132, 0, }, /* 988 */
+ { 132, 6, 12, 0, 0, 132, 0, }, /* 989 */
+ { 132, 13, 12, 0, 0, 132, 0, }, /* 990 */
+ { 132, 21, 12, 0, 0, 132, 0, }, /* 991 */
+ { 0, 2, 14, 0, 0, 0, 0, }, /* 992 */
+ { 10, 26, 11, 0, 0, 10, 0, }, /* 993 */
+ { 27, 26, 12, 0, 0, 27, 0, }, /* 994 */
+ { 10, 24, 3, 0, 0, 10, 0, }, /* 995 */
+ { 10, 1, 3, 0, 0, 10, 0, }, /* 996 */
};
const uint16_t PRIV(ucd_stage1)[] = { /* 17408 bytes */
@@ -1190,51 +1216,51 @@ const uint16_t PRIV(ucd_stage1)[] = { /* 17408 bytes */
98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+8000 */
98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+8800 */
98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+9000 */
- 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98,100, /* U+9800 */
-101,102,102,102,102,102,102,102,102,103,104,104,105,106,107,108, /* U+A000 */
-109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,117, /* U+A800 */
-118,119,120,121,122,123,117,118,119,120,121,122,123,117,118,119, /* U+B000 */
-120,121,122,123,117,118,119,120,121,122,123,117,118,119,120,121, /* U+B800 */
-122,123,117,118,119,120,121,122,123,117,118,119,120,121,122,123, /* U+C000 */
-117,118,119,120,121,122,123,117,118,119,120,121,122,123,117,118, /* U+C800 */
-119,120,121,122,123,117,118,119,120,121,122,123,117,118,119,124, /* U+D000 */
-125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+D800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+E000 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+E800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F000 */
-126,126, 98, 98,127,128,129,130,131,131,132,133,134,135,136,137, /* U+F800 */
-138,139,140,141,142,143,144,145,146,147,148,142,149,149,150,142, /* U+10000 */
-151,152,153,154,155,156,157,158,159,160,161,142,162,163,164,165, /* U+10800 */
-166,167,168,169,170,171,172,142,173,174,142,175,176,177,178,142, /* U+11000 */
-179,180,181,182,183,184,142,142,185,186,187,188,142,189,142,190, /* U+11800 */
-191,191,191,191,191,191,191,192,193,191,194,142,142,142,142,142, /* U+12000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+12800 */
-195,195,195,195,195,195,195,195,196,142,142,142,142,142,142,142, /* U+13000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+13800 */
-142,142,142,142,142,142,142,142,197,197,197,197,198,142,142,142, /* U+14000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+14800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+15000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+15800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+16000 */
-199,199,199,199,200,201,202,203,142,142,142,142,204,205,206,207, /* U+16800 */
-208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, /* U+17000 */
-208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, /* U+17800 */
-208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,209, /* U+18000 */
-208,208,208,208,208,208,210,210,210,211,212,142,142,142,142,142, /* U+18800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+19000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+19800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+1A000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+1A800 */
-213,214,215,216,216,217,142,142,142,142,142,142,142,142,142,142, /* U+1B000 */
-142,142,142,142,142,142,142,142,218,219,142,142,142,142,142,142, /* U+1B800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+1C000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+1C800 */
- 71,220,221,222,223,224,225,142,226,227,228,229,230,231,232,233, /* U+1D000 */
-234,234,234,234,235,236,142,142,142,142,142,142,142,142,142,142, /* U+1D800 */
-237,142,238,142,142,239,142,142,142,142,142,142,142,142,142,142, /* U+1E000 */
-240,241,242,142,142,142,142,142,243,244,245,142,246,247,142,142, /* U+1E800 */
-248,249,250,251,252,253,254,255,254,254,256,254,257,258,259,260, /* U+1F000 */
-261,262,263,264,265,266, 71,267,253,253,253,253,253,253,253,268, /* U+1F800 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+9800 */
+100,101,101,101,101,101,101,101,101,102,103,103,104,105,106,107, /* U+A000 */
+108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,116, /* U+A800 */
+117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118, /* U+B000 */
+119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120, /* U+B800 */
+121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122, /* U+C000 */
+116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117, /* U+C800 */
+118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,123, /* U+D000 */
+124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124, /* U+D800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+E000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+E800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F000 */
+125,125, 98, 98,126,127,128,129,130,130,131,132,133,134,135,136, /* U+F800 */
+137,138,139,140,141,142,143,144,145,146,147,148,149,149,150,151, /* U+10000 */
+152,153,154,155,156,157,158,159,160,161,162,141,163,164,165,166, /* U+10800 */
+167,168,169,170,171,172,173,141,174,175,141,176,177,178,179,141, /* U+11000 */
+180,181,182,183,184,185,141,141,186,187,188,189,141,190,141,191, /* U+11800 */
+192,192,192,192,192,192,192,193,194,192,195,141,141,141,141,141, /* U+12000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,196, /* U+12800 */
+197,197,197,197,197,197,197,197,198,141,141,141,141,141,141,141, /* U+13000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+13800 */
+141,141,141,141,141,141,141,141,199,199,199,199,200,141,141,141, /* U+14000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+14800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+15000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+15800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+16000 */
+201,201,201,201,202,203,204,205,141,141,141,141,206,207,208,209, /* U+16800 */
+210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, /* U+17000 */
+210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, /* U+17800 */
+210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,211, /* U+18000 */
+210,210,210,210,210,210,212,212,212,213,214,141,141,141,141,141, /* U+18800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+19000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+19800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+1A000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,215, /* U+1A800 */
+216,217,218,219,219,220,141,141,141,141,141,141,141,141,141,141, /* U+1B000 */
+141,141,141,141,141,141,141,141,221,222,141,141,141,141,141,141, /* U+1B800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+1C000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,223,224, /* U+1C800 */
+ 71,225,226,227,228,229,230,141,231,232,233,234,235,236,237,238, /* U+1D000 */
+239,239,239,239,240,241,141,141,141,141,141,141,141,141,242,141, /* U+1D800 */
+243,141,244,141,141,245,141,141,141,141,141,141,141,141,141,246, /* U+1E000 */
+247,248,249,141,141,141,141,141,250,251,252,141,253,254,141,141, /* U+1E800 */
+255,256,257,258,259,260,261,262,261,261,263,261,264,265,266,267, /* U+1F000 */
+268,269,270,261,271,272, 71,273,260,260,260,260,260,260,260,274, /* U+1F800 */
98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+20000 */
98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+20800 */
98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+21000 */
@@ -1255,469 +1281,469 @@ const uint16_t PRIV(ucd_stage1)[] = { /* 17408 bytes */
98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+28800 */
98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+29000 */
98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+29800 */
- 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98,269, 98, 98, /* U+2A000 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98,275, 98, 98, /* U+2A000 */
98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+2A800 */
- 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98,270, 98, /* U+2B000 */
-271, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+2B800 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98,276, 98, /* U+2B000 */
+277, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+2B800 */
98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+2C000 */
- 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98,272, 98, 98, /* U+2C800 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98,278, 98, 98, /* U+2C800 */
98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+2D000 */
98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+2D800 */
98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+2E000 */
- 98, 98, 98, 98, 98, 98, 98,273,142,142,142,142,142,142,142,142, /* U+2E800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+2F000 */
- 98, 98, 98, 98,274,142,142,142,142,142,142,142,142,142,142,142, /* U+2F800 */
+ 98, 98, 98, 98, 98, 98, 98,279,141,141,141,141,141,141,141,141, /* U+2E800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+2F000 */
+ 98, 98, 98, 98,280,141,141,141,141,141,141,141,141,141,141,141, /* U+2F800 */
98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+30000 */
98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+30800 */
- 98, 98, 98, 98, 98, 98,275,142,142,142,142,142,142,142,142,142, /* U+31000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+31800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+32000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+32800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+33000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+33800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+34000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+34800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+35000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+35800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+36000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+36800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+37000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+37800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+38000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+38800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+39000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+39800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+3A000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+3A800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+3B000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+3B800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+3C000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+3C800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+3D000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+3D800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+3E000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+3E800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+3F000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+3F800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+40000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+40800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+41000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+41800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+42000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+42800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+43000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+43800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+44000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+44800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+45000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+45800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+46000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+46800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+47000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+47800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+48000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+48800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+49000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+49800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+4A000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+4A800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+4B000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+4B800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+4C000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+4C800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+4D000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+4D800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+4E000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+4E800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+4F000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+4F800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+50000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+50800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+51000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+51800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+52000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+52800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+53000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+53800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+54000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+54800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+55000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+55800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+56000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+56800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+57000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+57800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+58000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+58800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+59000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+59800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+5A000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+5A800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+5B000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+5B800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+5C000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+5C800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+5D000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+5D800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+5E000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+5E800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+5F000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+5F800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+60000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+60800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+61000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+61800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+62000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+62800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+63000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+63800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+64000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+64800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+65000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+65800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+66000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+66800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+67000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+67800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+68000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+68800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+69000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+69800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+6A000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+6A800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+6B000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+6B800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+6C000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+6C800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+6D000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+6D800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+6E000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+6E800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+6F000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+6F800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+70000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+70800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+71000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+71800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+72000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+72800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+73000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+73800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+74000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+74800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+75000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+75800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+76000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+76800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+77000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+77800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+78000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+78800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+79000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+79800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+7A000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+7A800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+7B000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+7B800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+7C000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+7C800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+7D000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+7D800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+7E000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+7E800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+7F000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+7F800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+80000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+80800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+81000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+81800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+82000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+82800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+83000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+83800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+84000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+84800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+85000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+85800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+86000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+86800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+87000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+87800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+88000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+88800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+89000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+89800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+8A000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+8A800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+8B000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+8B800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+8C000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+8C800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+8D000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+8D800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+8E000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+8E800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+8F000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+8F800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+90000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+90800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+91000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+91800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+92000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+92800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+93000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+93800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+94000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+94800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+95000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+95800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+96000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+96800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+97000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+97800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+98000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+98800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+99000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+99800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+9A000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+9A800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+9B000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+9B800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+9C000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+9C800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+9D000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+9D800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+9E000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+9E800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+9F000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+9F800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A0000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A0800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A1000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A1800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A2000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A2800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A3000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A3800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A4000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A4800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A5000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A5800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A6000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A6800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A7000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A7800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A8000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A8800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A9000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A9800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+AA000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+AA800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+AB000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+AB800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+AC000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+AC800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+AD000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+AD800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+AE000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+AE800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+AF000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+AF800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B0000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B0800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B1000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B1800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B2000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B2800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B3000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B3800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B4000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B4800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B5000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B5800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B6000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B6800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B7000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B7800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B8000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B8800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B9000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B9800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+BA000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+BA800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+BB000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+BB800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+BC000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+BC800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+BD000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+BD800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+BE000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+BE800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+BF000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+BF800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C0000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C0800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C1000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C1800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C2000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C2800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C3000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C3800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C4000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C4800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C5000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C5800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C6000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C6800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C7000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C7800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C8000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C8800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C9000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C9800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+CA000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+CA800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+CB000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+CB800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+CC000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+CC800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+CD000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+CD800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+CE000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+CE800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+CF000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+CF800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D0000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D0800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D1000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D1800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D2000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D2800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D3000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D3800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D4000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D4800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D5000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D5800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D6000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D6800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D7000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D7800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D8000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D8800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D9000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D9800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+DA000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+DA800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+DB000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+DB800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+DC000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+DC800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+DD000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+DD800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+DE000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+DE800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+DF000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+DF800 */
-276,277,278,279,277,277,277,277,277,277,277,277,277,277,277,277, /* U+E0000 */
-277,277,277,277,277,277,277,277,277,277,277,277,277,277,277,277, /* U+E0800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E1000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E1800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E2000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E2800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E3000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E3800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E4000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E4800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E5000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E5800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E6000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E6800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E7000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E7800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E8000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E8800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E9000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E9800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+EA000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+EA800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+EB000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+EB800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+EC000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+EC800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+ED000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+ED800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+EE000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+EE800 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+EF000 */
-142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+EF800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F0000 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F0800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F1000 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F1800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F2000 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F2800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F3000 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F3800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F4000 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F4800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F5000 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F5800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F6000 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F6800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F7000 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F7800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F8000 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F8800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F9000 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F9800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+FA000 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+FA800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+FB000 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+FB800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+FC000 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+FC800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+FD000 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+FD800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+FE000 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+FE800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+FF000 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,280, /* U+FF800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+100000 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+100800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+101000 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+101800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+102000 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+102800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+103000 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+103800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+104000 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+104800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+105000 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+105800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+106000 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+106800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+107000 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+107800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+108000 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+108800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+109000 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+109800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+10A000 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+10A800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+10B000 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+10B800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+10C000 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+10C800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+10D000 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+10D800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+10E000 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+10E800 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+10F000 */
-126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,280, /* U+10F800 */
+ 98, 98, 98, 98, 98, 98,281,141,141,141,141,141,141,141,141,141, /* U+31000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+31800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+32000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+32800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+33000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+33800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+34000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+34800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+35000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+35800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+36000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+36800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+37000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+37800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+38000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+38800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+39000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+39800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+3A000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+3A800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+3B000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+3B800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+3C000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+3C800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+3D000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+3D800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+3E000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+3E800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+3F000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+3F800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+40000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+40800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+41000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+41800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+42000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+42800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+43000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+43800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+44000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+44800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+45000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+45800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+46000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+46800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+47000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+47800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+48000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+48800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+49000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+49800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+4A000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+4A800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+4B000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+4B800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+4C000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+4C800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+4D000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+4D800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+4E000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+4E800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+4F000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+4F800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+50000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+50800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+51000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+51800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+52000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+52800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+53000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+53800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+54000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+54800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+55000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+55800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+56000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+56800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+57000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+57800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+58000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+58800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+59000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+59800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+5A000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+5A800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+5B000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+5B800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+5C000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+5C800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+5D000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+5D800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+5E000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+5E800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+5F000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+5F800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+60000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+60800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+61000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+61800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+62000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+62800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+63000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+63800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+64000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+64800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+65000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+65800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+66000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+66800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+67000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+67800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+68000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+68800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+69000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+69800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+6A000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+6A800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+6B000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+6B800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+6C000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+6C800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+6D000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+6D800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+6E000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+6E800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+6F000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+6F800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+70000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+70800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+71000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+71800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+72000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+72800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+73000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+73800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+74000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+74800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+75000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+75800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+76000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+76800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+77000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+77800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+78000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+78800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+79000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+79800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+7A000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+7A800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+7B000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+7B800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+7C000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+7C800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+7D000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+7D800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+7E000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+7E800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+7F000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+7F800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+80000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+80800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+81000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+81800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+82000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+82800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+83000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+83800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+84000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+84800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+85000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+85800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+86000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+86800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+87000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+87800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+88000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+88800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+89000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+89800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+8A000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+8A800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+8B000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+8B800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+8C000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+8C800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+8D000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+8D800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+8E000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+8E800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+8F000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+8F800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+90000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+90800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+91000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+91800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+92000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+92800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+93000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+93800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+94000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+94800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+95000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+95800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+96000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+96800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+97000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+97800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+98000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+98800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+99000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+99800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+9A000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+9A800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+9B000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+9B800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+9C000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+9C800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+9D000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+9D800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+9E000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+9E800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+9F000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+9F800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A0000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A0800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A1000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A1800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A2000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A2800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A3000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A3800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A4000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A4800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A5000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A5800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A6000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A6800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A7000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A7800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A8000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A8800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A9000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A9800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+AA000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+AA800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+AB000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+AB800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+AC000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+AC800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+AD000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+AD800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+AE000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+AE800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+AF000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+AF800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B0000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B0800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B1000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B1800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B2000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B2800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B3000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B3800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B4000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B4800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B5000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B5800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B6000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B6800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B7000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B7800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B8000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B8800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B9000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B9800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+BA000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+BA800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+BB000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+BB800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+BC000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+BC800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+BD000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+BD800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+BE000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+BE800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+BF000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+BF800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C0000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C0800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C1000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C1800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C2000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C2800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C3000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C3800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C4000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C4800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C5000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C5800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C6000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C6800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C7000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C7800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C8000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C8800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C9000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C9800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+CA000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+CA800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+CB000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+CB800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+CC000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+CC800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+CD000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+CD800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+CE000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+CE800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+CF000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+CF800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D0000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D0800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D1000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D1800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D2000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D2800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D3000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D3800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D4000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D4800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D5000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D5800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D6000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D6800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D7000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D7800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D8000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D8800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D9000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D9800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+DA000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+DA800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+DB000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+DB800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+DC000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+DC800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+DD000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+DD800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+DE000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+DE800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+DF000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+DF800 */
+282,283,284,285,283,283,283,283,283,283,283,283,283,283,283,283, /* U+E0000 */
+283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283, /* U+E0800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E1000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E1800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E2000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E2800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E3000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E3800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E4000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E4800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E5000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E5800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E6000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E6800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E7000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E7800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E8000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E8800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E9000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E9800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+EA000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+EA800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+EB000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+EB800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+EC000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+EC800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+ED000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+ED800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+EE000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+EE800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+EF000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+EF800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F0000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F0800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F1000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F1800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F2000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F2800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F3000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F3800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F4000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F4800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F5000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F5800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F6000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F6800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F7000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F7800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F8000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F8800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F9000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F9800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+FA000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+FA800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+FB000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+FB800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+FC000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+FC800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+FD000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+FD800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+FE000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+FE800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+FF000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,286, /* U+FF800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+100000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+100800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+101000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+101800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+102000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+102800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+103000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+103800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+104000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+104800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+105000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+105800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+106000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+106800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+107000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+107800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+108000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+108800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+109000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+109800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+10A000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+10A800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+10B000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+10B800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+10C000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+10C800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+10D000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+10D800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+10E000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+10E800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+10F000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,286, /* U+10F800 */
};
-const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
+const uint16_t PRIV(ucd_stage2)[] = { /* 73472 bytes, block = 128 */
/* block 0 */
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 3, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -1840,463 +1866,463 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
/* block 12 */
215,215,215,215,215,216,217,217,217,218,218,219,220,218,221,221,
-222,222,222,222,222,222,222,222,222,222,222,220,223,120,218,220,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-225,224,224,224,224,224,224,224,224,224,224,226,226,226,226,226,
-226,226,226,226,226,226,222,222,222,222,222,222,222,222,222,222,
-227,227,227,227,227,227,227,227,227,227,218,218,218,218,224,224,
-226,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+222,222,222,222,222,222,222,222,222,222,222,220,223,218,218,224,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+226,225,225,225,225,225,225,225,225,225,225,227,227,227,227,227,
+227,227,227,227,227,227,222,222,222,222,222,222,222,222,222,222,
+228,228,228,228,228,228,228,228,228,228,218,218,218,218,225,225,
+227,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
/* block 13 */
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,228,224,222,222,222,222,222,222,222,216,221,222,
-222,222,222,222,222,229,229,222,222,221,222,222,222,222,224,224,
-230,230,230,230,230,230,230,230,230,230,224,224,224,221,221,224,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,229,225,222,222,222,222,222,222,222,216,221,222,
+222,222,222,222,222,230,230,222,222,221,222,222,222,222,225,225,
+231,231,231,231,231,231,231,231,231,231,225,225,225,221,221,225,
/* block 14 */
-231,231,231,231,231,231,231,231,231,231,231,231,231,231,120,232,
-233,234,233,233,233,233,233,233,233,233,233,233,233,233,233,233,
-233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,
+232,232,232,232,232,232,232,232,232,232,232,232,232,232,120,233,
+234,235,234,234,234,234,234,234,234,234,234,234,234,234,234,234,
234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,
-234,234,234,234,234,234,234,234,234,234,234,120,120,233,233,233,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,
+235,235,235,235,235,235,235,235,235,235,235,120,120,234,234,234,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
/* block 15 */
-235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,
-235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,
-235,235,235,235,235,235,236,236,236,236,236,236,236,236,236,236,
-236,235,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-237,237,237,237,237,237,237,237,237,237,238,238,238,238,238,238,
-238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,
-238,238,238,238,238,238,238,238,238,238,238,239,239,239,239,239,
-239,239,239,239,240,240,241,242,242,242,240,120,120,239,243,243,
+236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,
+236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,
+236,236,236,236,236,236,237,237,237,237,237,237,237,237,237,237,
+237,236,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+238,238,238,238,238,238,238,238,238,238,239,239,239,239,239,239,
+239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,
+239,239,239,239,239,239,239,239,239,239,239,240,240,240,240,240,
+240,240,240,240,241,241,242,243,243,243,241,120,120,240,244,244,
/* block 16 */
-244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,
-244,244,244,244,244,244,245,245,245,245,246,245,245,245,245,245,
-245,245,245,245,246,245,245,245,246,245,245,245,245,245,120,120,
-247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,120,
-248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,
-248,248,248,248,248,248,248,248,248,249,249,249,120,120,250,120,
-233,233,233,233,233,233,233,233,233,233,233,120,120,120,120,120,
-120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,
+245,245,245,245,245,245,246,246,246,246,247,246,246,246,246,246,
+246,246,246,246,247,246,246,246,247,246,246,246,246,246,120,120,
+248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,120,
+249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,
+249,249,249,249,249,249,249,249,249,250,250,250,120,120,251,120,
+234,234,234,234,234,234,234,234,234,234,234,120,120,120,120,120,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
/* block 17 */
-120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,120,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,120,120,120,120,120,120,120,120,
-120,120,120,222,222,222,222,222,222,222,222,222,222,222,222,222,
+225,225,225,225,225,225,225,225,252,225,225,225,225,225,225,120,
+215,215,120,120,120,120,120,120,222,222,222,222,222,222,222,222,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,230,222,222,222,222,222,222,
+222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,
222,222,216,222,222,222,222,222,222,222,222,222,222,222,222,222,
222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,
/* block 18 */
-251,251,251,252,253,253,253,253,253,253,253,253,253,253,253,253,
-253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,
-253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,
-253,253,253,253,253,253,253,253,253,253,251,252,251,253,252,252,
-252,251,251,251,251,251,251,251,251,252,252,252,252,251,252,252,
-253,254,255,113,113,251,251,251,253,253,253,253,253,253,253,253,
-253,253,251,251,256,257,258,258,258,258,258,258,258,258,258,258,
-259,260,253,253,253,253,253,253,253,253,253,253,253,253,253,253,
+253,253,253,254,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,253,254,253,255,254,254,
+254,253,253,253,253,253,253,253,253,254,254,254,254,253,254,254,
+255,256,257,113,113,253,253,253,255,255,255,255,255,255,255,255,
+255,255,253,253,258,259,260,260,260,260,260,260,260,260,260,260,
+261,262,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
/* block 19 */
-261,262,263,263,120,261,261,261,261,261,261,261,261,120,120,261,
-261,120,120,261,261,261,261,261,261,261,261,261,261,261,261,261,
-261,261,261,261,261,261,261,261,261,120,261,261,261,261,261,261,
-261,120,261,120,120,120,261,261,261,261,120,120,262,261,264,263,
-263,262,262,262,262,120,120,263,263,120,120,263,263,262,261,120,
-120,120,120,120,120,120,120,264,120,120,120,120,261,261,120,261,
-261,261,262,262,120,120,265,265,265,265,265,265,265,265,265,265,
-261,261,266,266,267,267,267,267,267,267,268,266,261,269,262,120,
+263,264,265,265,120,263,263,263,263,263,263,263,263,120,120,263,
+263,120,120,263,263,263,263,263,263,263,263,263,263,263,263,263,
+263,263,263,263,263,263,263,263,263,120,263,263,263,263,263,263,
+263,120,263,120,120,120,263,263,263,263,120,120,264,263,266,265,
+265,264,264,264,264,120,120,265,265,120,120,265,265,264,263,120,
+120,120,120,120,120,120,120,266,120,120,120,120,263,263,120,263,
+263,263,264,264,120,120,267,267,267,267,267,267,267,267,267,267,
+263,263,268,268,269,269,269,269,269,269,270,268,263,271,264,120,
/* block 20 */
-120,270,270,271,120,272,272,272,272,272,272,120,120,120,120,272,
-272,120,120,272,272,272,272,272,272,272,272,272,272,272,272,272,
-272,272,272,272,272,272,272,272,272,120,272,272,272,272,272,272,
-272,120,272,272,120,272,272,120,272,272,120,120,270,120,271,271,
-271,270,270,120,120,120,120,270,270,120,120,270,270,270,120,120,
-120,270,120,120,120,120,120,120,120,272,272,272,272,120,272,120,
-120,120,120,120,120,120,273,273,273,273,273,273,273,273,273,273,
-270,270,272,272,272,270,274,120,120,120,120,120,120,120,120,120,
+120,272,272,273,120,274,274,274,274,274,274,120,120,120,120,274,
+274,120,120,274,274,274,274,274,274,274,274,274,274,274,274,274,
+274,274,274,274,274,274,274,274,274,120,274,274,274,274,274,274,
+274,120,274,274,120,274,274,120,274,274,120,120,272,120,273,273,
+273,272,272,120,120,120,120,272,272,120,120,272,272,272,120,120,
+120,272,120,120,120,120,120,120,120,274,274,274,274,120,274,120,
+120,120,120,120,120,120,275,275,275,275,275,275,275,275,275,275,
+272,272,274,274,274,272,276,120,120,120,120,120,120,120,120,120,
/* block 21 */
-120,275,275,276,120,277,277,277,277,277,277,277,277,277,120,277,
-277,277,120,277,277,277,277,277,277,277,277,277,277,277,277,277,
-277,277,277,277,277,277,277,277,277,120,277,277,277,277,277,277,
-277,120,277,277,120,277,277,277,277,277,120,120,275,277,276,276,
-276,275,275,275,275,275,120,275,275,276,120,276,276,275,120,120,
-277,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-277,277,275,275,120,120,278,278,278,278,278,278,278,278,278,278,
-279,280,120,120,120,120,120,120,120,277,275,275,275,275,275,275,
+120,277,277,278,120,279,279,279,279,279,279,279,279,279,120,279,
+279,279,120,279,279,279,279,279,279,279,279,279,279,279,279,279,
+279,279,279,279,279,279,279,279,279,120,279,279,279,279,279,279,
+279,120,279,279,120,279,279,279,279,279,120,120,277,279,278,278,
+278,277,277,277,277,277,120,277,277,278,120,278,278,277,120,120,
+279,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+279,279,277,277,120,120,280,280,280,280,280,280,280,280,280,280,
+281,282,120,120,120,120,120,120,120,279,277,277,277,277,277,277,
/* block 22 */
-120,281,282,282,120,283,283,283,283,283,283,283,283,120,120,283,
-283,120,120,283,283,283,283,283,283,283,283,283,283,283,283,283,
-283,283,283,283,283,283,283,283,283,120,283,283,283,283,283,283,
-283,120,283,283,120,283,283,283,283,283,120,120,281,283,284,281,
-282,281,281,281,281,120,120,282,282,120,120,282,282,281,120,120,
-120,120,120,120,120,281,281,284,120,120,120,120,283,283,120,283,
-283,283,281,281,120,120,285,285,285,285,285,285,285,285,285,285,
-286,283,287,287,287,287,287,287,120,120,120,120,120,120,120,120,
+120,283,284,284,120,285,285,285,285,285,285,285,285,120,120,285,
+285,120,120,285,285,285,285,285,285,285,285,285,285,285,285,285,
+285,285,285,285,285,285,285,285,285,120,285,285,285,285,285,285,
+285,120,285,285,120,285,285,285,285,285,120,120,283,285,286,283,
+284,283,283,283,283,120,120,284,284,120,120,284,284,283,120,120,
+120,120,120,120,120,283,283,286,120,120,120,120,285,285,120,285,
+285,285,283,283,120,120,287,287,287,287,287,287,287,287,287,287,
+288,285,289,289,289,289,289,289,120,120,120,120,120,120,120,120,
/* block 23 */
-120,120,288,289,120,289,289,289,289,289,289,120,120,120,289,289,
-289,120,289,289,289,289,120,120,120,289,289,120,289,120,289,289,
-120,120,120,289,289,120,120,120,289,289,289,120,120,120,289,289,
-289,289,289,289,289,289,289,289,289,289,120,120,120,120,290,291,
-288,291,291,120,120,120,291,291,291,120,291,291,291,288,120,120,
-289,120,120,120,120,120,120,290,120,120,120,120,120,120,120,120,
-120,120,120,120,120,120,292,292,292,292,292,292,292,292,292,292,
-293,293,293,294,295,295,295,295,295,296,295,120,120,120,120,120,
+120,120,290,291,120,291,291,291,291,291,291,120,120,120,291,291,
+291,120,291,291,291,291,120,120,120,291,291,120,291,120,291,291,
+120,120,120,291,291,120,120,120,291,291,291,120,120,120,291,291,
+291,291,291,291,291,291,291,291,291,291,120,120,120,120,292,293,
+290,293,293,120,120,120,293,293,293,120,293,293,293,290,120,120,
+291,120,120,120,120,120,120,292,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,294,294,294,294,294,294,294,294,294,294,
+295,295,295,296,297,297,297,297,297,298,297,120,120,120,120,120,
/* block 24 */
-297,298,298,298,297,299,299,299,299,299,299,299,299,120,299,299,
-299,120,299,299,299,299,299,299,299,299,299,299,299,299,299,299,
-299,299,299,299,299,299,299,299,299,120,299,299,299,299,299,299,
-299,299,299,299,299,299,299,299,299,299,120,120,120,299,297,297,
-297,298,298,298,298,120,297,297,297,120,297,297,297,297,120,120,
-120,120,120,120,120,297,297,120,299,299,299,120,120,120,120,120,
-299,299,297,297,120,120,300,300,300,300,300,300,300,300,300,300,
-120,120,120,120,120,120,120,301,302,302,302,302,302,302,302,303,
+299,300,300,300,299,301,301,301,301,301,301,301,301,120,301,301,
+301,120,301,301,301,301,301,301,301,301,301,301,301,301,301,301,
+301,301,301,301,301,301,301,301,301,120,301,301,301,301,301,301,
+301,301,301,301,301,301,301,301,301,301,120,120,299,301,299,299,
+299,300,300,300,300,120,299,299,299,120,299,299,299,299,120,120,
+120,120,120,120,120,299,299,120,301,301,301,120,120,301,120,120,
+301,301,299,299,120,120,302,302,302,302,302,302,302,302,302,302,
+120,120,120,120,120,120,120,303,304,304,304,304,304,304,304,305,
/* block 25 */
-304,305,306,306,307,304,304,304,304,304,304,304,304,120,304,304,
-304,120,304,304,304,304,304,304,304,304,304,304,304,304,304,304,
-304,304,304,304,304,304,304,304,304,120,304,304,304,304,304,304,
-304,304,304,304,120,304,304,304,304,304,120,120,305,304,306,305,
-306,306,308,306,306,120,305,306,306,120,306,306,305,305,120,120,
-120,120,120,120,120,308,308,120,120,120,120,120,120,120,304,120,
-304,304,305,305,120,120,309,309,309,309,309,309,309,309,309,309,
-120,304,304,120,120,120,120,120,120,120,120,120,120,120,120,120,
+306,307,308,308,309,306,306,306,306,306,306,306,306,120,306,306,
+306,120,306,306,306,306,306,306,306,306,306,306,306,306,306,306,
+306,306,306,306,306,306,306,306,306,120,306,306,306,306,306,306,
+306,306,306,306,120,306,306,306,306,306,120,120,307,306,308,307,
+308,308,310,308,308,120,307,308,308,120,308,308,307,307,120,120,
+120,120,120,120,120,310,310,120,120,120,120,120,120,306,306,120,
+306,306,307,307,120,120,311,311,311,311,311,311,311,311,311,311,
+120,306,306,120,120,120,120,120,120,120,120,120,120,120,120,120,
/* block 26 */
-310,310,311,311,312,312,312,312,312,312,312,312,312,120,312,312,
-312,120,312,312,312,312,312,312,312,312,312,312,312,312,312,312,
-312,312,312,312,312,312,312,312,312,312,312,312,312,312,312,312,
-312,312,312,312,312,312,312,312,312,312,312,310,310,312,313,311,
-311,310,310,310,310,120,311,311,311,120,311,311,311,310,314,315,
-120,120,120,120,312,312,312,313,316,316,316,316,316,316,316,312,
-312,312,310,310,120,120,317,317,317,317,317,317,317,317,317,317,
-316,316,316,316,316,316,316,316,316,315,312,312,312,312,312,312,
+312,312,313,313,314,314,314,314,314,314,314,314,314,120,314,314,
+314,120,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
+314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
+314,314,314,314,314,314,314,314,314,314,314,312,312,314,315,313,
+313,312,312,312,312,120,313,313,313,120,313,313,313,312,316,317,
+120,120,120,120,314,314,314,315,318,318,318,318,318,318,318,314,
+314,314,312,312,120,120,319,319,319,319,319,319,319,319,319,319,
+318,318,318,318,318,318,318,318,318,317,314,314,314,314,314,314,
/* block 27 */
-120,318,319,319,120,320,320,320,320,320,320,320,320,320,320,320,
-320,320,320,320,320,320,320,120,120,120,320,320,320,320,320,320,
-320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,
-320,320,120,320,320,320,320,320,320,320,320,320,120,320,120,120,
-320,320,320,320,320,320,320,120,120,120,318,120,120,120,120,321,
-319,319,318,318,318,120,318,120,319,319,319,319,319,319,319,321,
-120,120,120,120,120,120,322,322,322,322,322,322,322,322,322,322,
-120,120,319,319,323,120,120,120,120,120,120,120,120,120,120,120,
+120,320,321,321,120,322,322,322,322,322,322,322,322,322,322,322,
+322,322,322,322,322,322,322,120,120,120,322,322,322,322,322,322,
+322,322,322,322,322,322,322,322,322,322,322,322,322,322,322,322,
+322,322,120,322,322,322,322,322,322,322,322,322,120,322,120,120,
+322,322,322,322,322,322,322,120,120,120,320,120,120,120,120,323,
+321,321,320,320,320,120,320,120,321,321,321,321,321,321,321,323,
+120,120,120,120,120,120,324,324,324,324,324,324,324,324,324,324,
+120,120,321,321,325,120,120,120,120,120,120,120,120,120,120,120,
/* block 28 */
-120,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,
-324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,
-324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,
-324,325,324,326,325,325,325,325,325,325,325,120,120,120,120, 6,
-324,324,324,324,324,324,327,325,325,325,325,325,325,325,325,328,
-329,329,329,329,329,329,329,329,329,329,328,328,120,120,120,120,
+120,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,
+326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,
+326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,326,
+326,327,326,328,327,327,327,327,327,327,327,120,120,120,120, 6,
+326,326,326,326,326,326,329,327,327,327,327,327,327,327,327,330,
+331,331,331,331,331,331,331,331,331,331,330,330,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
/* block 29 */
-120,330,330,120,330,120,330,330,330,330,330,120,330,330,330,330,
-330,330,330,330,330,330,330,330,330,330,330,330,330,330,330,330,
-330,330,330,330,120,330,120,330,330,330,330,330,330,330,330,330,
-330,331,330,332,331,331,331,331,331,331,331,331,331,330,120,120,
-330,330,330,330,330,120,333,120,331,331,331,331,331,331,120,120,
-334,334,334,334,334,334,334,334,334,334,120,120,330,330,330,330,
+120,332,332,120,332,120,332,332,332,332,332,120,332,332,332,332,
+332,332,332,332,332,332,332,332,332,332,332,332,332,332,332,332,
+332,332,332,332,120,332,120,332,332,332,332,332,332,332,332,332,
+332,333,332,334,333,333,333,333,333,333,333,333,333,332,120,120,
+332,332,332,332,332,120,335,120,333,333,333,333,333,333,120,120,
+336,336,336,336,336,336,336,336,336,336,120,120,332,332,332,332,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
/* block 30 */
-335,336,336,336,337,337,337,337,337,337,337,337,337,337,337,337,
-337,337,337,336,337,336,336,336,338,338,336,336,336,336,336,336,
-339,339,339,339,339,339,339,339,339,339,340,340,340,340,340,340,
-340,340,340,340,336,338,336,338,336,338,341,342,341,342,343,343,
-335,335,335,335,335,335,335,335,120,335,335,335,335,335,335,335,
-335,335,335,335,335,335,335,335,335,335,335,335,335,335,335,335,
-335,335,335,335,335,335,335,335,335,335,335,335,335,120,120,120,
-120,338,338,338,338,338,338,338,338,338,338,338,338,338,338,343,
+337,338,338,338,339,339,339,339,339,339,339,339,339,339,339,339,
+339,339,339,338,339,338,338,338,340,340,338,338,338,338,338,338,
+341,341,341,341,341,341,341,341,341,341,342,342,342,342,342,342,
+342,342,342,342,338,340,338,340,338,340,343,344,343,344,345,345,
+337,337,337,337,337,337,337,337,120,337,337,337,337,337,337,337,
+337,337,337,337,337,337,337,337,337,337,337,337,337,337,337,337,
+337,337,337,337,337,337,337,337,337,337,337,337,337,120,120,120,
+120,340,340,340,340,340,340,340,340,340,340,340,340,340,340,345,
/* block 31 */
-338,338,338,338,338,337,338,338,335,335,335,335,335,338,338,338,
-338,338,338,338,338,338,338,338,120,338,338,338,338,338,338,338,
-338,338,338,338,338,338,338,338,338,338,338,338,338,338,338,338,
-338,338,338,338,338,338,338,338,338,338,338,338,338,120,336,336,
-336,336,336,336,336,336,338,336,336,336,336,336,336,120,336,336,
-337,337,337,337,337, 20, 20, 20, 20,337,337,120,120,120,120,120,
+340,340,340,340,340,339,340,340,337,337,337,337,337,340,340,340,
+340,340,340,340,340,340,340,340,120,340,340,340,340,340,340,340,
+340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,
+340,340,340,340,340,340,340,340,340,340,340,340,340,120,338,338,
+338,338,338,338,338,338,340,338,338,338,338,338,338,120,338,338,
+339,339,339,339,339, 20, 20, 20, 20,339,339,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
/* block 32 */
-344,344,344,344,344,344,344,344,344,344,344,344,344,344,344,344,
-344,344,344,344,344,344,344,344,344,344,344,344,344,344,344,344,
-344,344,344,344,344,344,344,344,344,344,344,345,345,346,346,346,
-346,347,346,346,346,346,346,346,345,346,346,347,347,346,346,344,
-348,348,348,348,348,348,348,348,348,348,349,349,349,349,349,349,
-344,344,344,344,344,344,347,347,346,346,344,344,344,344,346,346,
-346,344,345,345,345,344,344,345,345,345,345,345,345,345,344,344,
-344,346,346,346,346,344,344,344,344,344,344,344,344,344,344,344,
+346,346,346,346,346,346,346,346,346,346,346,346,346,346,346,346,
+346,346,346,346,346,346,346,346,346,346,346,346,346,346,346,346,
+346,346,346,346,346,346,346,346,346,346,346,347,347,348,348,348,
+348,349,348,348,348,348,348,348,347,348,348,349,349,348,348,346,
+350,350,350,350,350,350,350,350,350,350,351,351,351,351,351,351,
+346,346,346,346,346,346,349,349,348,348,346,346,346,346,348,348,
+348,346,347,347,347,346,346,347,347,347,347,347,347,347,346,346,
+346,348,348,348,348,346,346,346,346,346,346,346,346,346,346,346,
/* block 33 */
-344,344,346,345,347,346,346,345,345,345,345,345,345,346,344,345,
-350,350,350,350,350,350,350,350,350,350,345,345,345,346,351,351,
-352,352,352,352,352,352,352,352,352,352,352,352,352,352,352,352,
-352,352,352,352,352,352,352,352,352,352,352,352,352,352,352,352,
-352,352,352,352,352,352,120,352,120,120,120,120,120,352,120,120,
-353,353,353,353,353,353,353,353,353,353,353,353,353,353,353,353,
-353,353,353,353,353,353,353,353,353,353,353,353,353,353,353,353,
-353,353,353,353,353,353,353,353,353,353,353,354,355,353,353,353,
+346,346,348,347,349,348,348,347,347,347,347,347,347,348,346,347,
+352,352,352,352,352,352,352,352,352,352,347,347,347,348,353,353,
+354,354,354,354,354,354,354,354,354,354,354,354,354,354,354,354,
+354,354,354,354,354,354,354,354,354,354,354,354,354,354,354,354,
+354,354,354,354,354,354,120,354,120,120,120,120,120,354,120,120,
+355,355,355,355,355,355,355,355,355,355,355,355,355,355,355,355,
+355,355,355,355,355,355,355,355,355,355,355,355,355,355,355,355,
+355,355,355,355,355,355,355,355,355,355,355,356,357,355,355,355,
/* block 34 */
-356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,
-356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,
-356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,
-356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,
-356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,
-356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,
-357,357,357,357,357,357,357,357,357,357,357,357,357,357,357,357,
-357,357,357,357,357,357,357,357,357,357,357,357,357,357,357,357,
-
-/* block 35 */
-357,357,357,357,357,357,357,357,357,357,357,357,357,357,357,357,
-357,357,357,357,357,357,357,357,357,357,357,357,357,357,357,357,
-357,357,357,357,357,357,357,357,358,358,358,358,358,358,358,358,
358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,
358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,
358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,
358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,
358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,
-
-/* block 36 */
-359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
-359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
+358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,
359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
-359,359,359,359,359,359,359,359,359,120,359,359,359,359,120,120,
-359,359,359,359,359,359,359,120,359,120,359,359,359,359,120,120,
+
+/* block 35 */
359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
+359,359,359,359,359,359,359,359,360,360,360,360,360,360,360,360,
+360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,
+360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,
+360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,
+360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,
+360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,
+
+/* block 36 */
+361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,
+361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,
+361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,
+361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,
+361,361,361,361,361,361,361,361,361,120,361,361,361,361,120,120,
+361,361,361,361,361,361,361,120,361,120,361,361,361,361,120,120,
+361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,
+361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,
/* block 37 */
-359,359,359,359,359,359,359,359,359,120,359,359,359,359,120,120,
-359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
-359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
-359,120,359,359,359,359,120,120,359,359,359,359,359,359,359,120,
-359,120,359,359,359,359,120,120,359,359,359,359,359,359,359,359,
-359,359,359,359,359,359,359,120,359,359,359,359,359,359,359,359,
-359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
-359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
+361,361,361,361,361,361,361,361,361,120,361,361,361,361,120,120,
+361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,
+361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,
+361,120,361,361,361,361,120,120,361,361,361,361,361,361,361,120,
+361,120,361,361,361,361,120,120,361,361,361,361,361,361,361,361,
+361,361,361,361,361,361,361,120,361,361,361,361,361,361,361,361,
+361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,
+361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,
/* block 38 */
-359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
-359,120,359,359,359,359,120,120,359,359,359,359,359,359,359,359,
-359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
-359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
-359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
-359,359,359,359,359,359,359,359,359,359,359,120,120,360,360,360,
-361,361,361,361,361,361,361,361,361,362,362,362,362,362,362,362,
-362,362,362,362,362,362,362,362,362,362,362,362,362,120,120,120,
+361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,
+361,120,361,361,361,361,120,120,361,361,361,361,361,361,361,361,
+361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,
+361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,
+361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,
+361,361,361,361,361,361,361,361,361,361,361,120,120,362,362,362,
+363,363,363,363,363,363,363,363,363,364,364,364,364,364,364,364,
+364,364,364,364,364,364,364,364,364,364,364,364,364,120,120,120,
/* block 39 */
-359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
-363,363,363,363,363,363,363,363,363,363,120,120,120,120,120,120,
-364,364,364,364,364,364,364,364,364,364,364,364,364,364,364,364,
-364,364,364,364,364,364,364,364,364,364,364,364,364,364,364,364,
-364,364,364,364,364,364,364,364,364,364,364,364,364,364,364,364,
-364,364,364,364,364,364,364,364,364,364,364,364,364,364,364,364,
-364,364,364,364,364,364,364,364,364,364,364,364,364,364,364,364,
-365,365,365,365,365,365,120,120,366,366,366,366,366,366,120,120,
+361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,
+365,365,365,365,365,365,365,365,365,365,120,120,120,120,120,120,
+366,366,366,366,366,366,366,366,366,366,366,366,366,366,366,366,
+366,366,366,366,366,366,366,366,366,366,366,366,366,366,366,366,
+366,366,366,366,366,366,366,366,366,366,366,366,366,366,366,366,
+366,366,366,366,366,366,366,366,366,366,366,366,366,366,366,366,
+366,366,366,366,366,366,366,366,366,366,366,366,366,366,366,366,
+367,367,367,367,367,367,120,120,368,368,368,368,368,368,120,120,
/* block 40 */
-367,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
-368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
-368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
-368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
-368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
-368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
-368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
-368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
+369,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,
+370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,
+370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,
+370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,
+370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,
+370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,
+370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,
+370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,
/* block 41 */
-368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
-368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
-368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
-368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
-368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
-368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
-368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
-368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
+370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,
+370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,
+370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,
+370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,
+370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,
+370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,
+370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,
+370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,
/* block 42 */
-368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
-368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
-368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
-368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
-368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
-368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
-368,368,368,368,368,368,368,368,368,368,368,368,368,369,370,368,
-368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
+370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,
+370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,
+370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,
+370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,
+370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,
+370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,
+370,370,370,370,370,370,370,370,370,370,370,370,370,371,372,370,
+370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,
/* block 43 */
-371,372,372,372,372,372,372,372,372,372,372,372,372,372,372,372,
-372,372,372,372,372,372,372,372,372,372,372,373,374,120,120,120,
-375,375,375,375,375,375,375,375,375,375,375,375,375,375,375,375,
-375,375,375,375,375,375,375,375,375,375,375,375,375,375,375,375,
-375,375,375,375,375,375,375,375,375,375,375,375,375,375,375,375,
-375,375,375,375,375,375,375,375,375,375,375,375,375,375,375,375,
-375,375,375,375,375,375,375,375,375,375,375, 5, 5, 5,376,376,
-376,375,375,375,375,375,375,375,375,120,120,120,120,120,120,120,
+373,374,374,374,374,374,374,374,374,374,374,374,374,374,374,374,
+374,374,374,374,374,374,374,374,374,374,374,375,376,120,120,120,
+377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,
+377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,
+377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,
+377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,377,
+377,377,377,377,377,377,377,377,377,377,377, 5, 5, 5,378,378,
+378,377,377,377,377,377,377,377,377,120,120,120,120,120,120,120,
/* block 44 */
-377,377,377,377,377,377,377,377,377,377,377,377,377,120,377,377,
-377,377,378,378,378,120,120,120,120,120,120,120,120,120,120,120,
379,379,379,379,379,379,379,379,379,379,379,379,379,379,379,379,
-379,379,380,380,380,381,381,120,120,120,120,120,120,120,120,120,
+379,379,380,380,380,381,120,120,120,120,120,120,120,120,120,379,
382,382,382,382,382,382,382,382,382,382,382,382,382,382,382,382,
-382,382,383,383,120,120,120,120,120,120,120,120,120,120,120,120,
-384,384,384,384,384,384,384,384,384,384,384,384,384,120,384,384,
-384,120,385,385,120,120,120,120,120,120,120,120,120,120,120,120,
+382,382,383,383,384,385,385,120,120,120,120,120,120,120,120,120,
+386,386,386,386,386,386,386,386,386,386,386,386,386,386,386,386,
+386,386,387,387,120,120,120,120,120,120,120,120,120,120,120,120,
+388,388,388,388,388,388,388,388,388,388,388,388,388,120,388,388,
+388,120,389,389,120,120,120,120,120,120,120,120,120,120,120,120,
/* block 45 */
-386,386,386,386,386,386,386,386,386,386,386,386,386,386,386,386,
-386,386,386,386,386,386,386,386,386,386,386,386,386,386,386,386,
-386,386,386,386,386,386,386,386,386,386,386,386,386,386,386,386,
-386,386,386,386,387,387,388,387,387,387,387,387,387,387,388,388,
-388,388,388,388,388,388,387,388,388,387,387,387,387,387,387,387,
-387,387,387,387,389,389,389,390,389,389,389,391,386,387,120,120,
-392,392,392,392,392,392,392,392,392,392,120,120,120,120,120,120,
-393,393,393,393,393,393,393,393,393,393,120,120,120,120,120,120,
+390,390,390,390,390,390,390,390,390,390,390,390,390,390,390,390,
+390,390,390,390,390,390,390,390,390,390,390,390,390,390,390,390,
+390,390,390,390,390,390,390,390,390,390,390,390,390,390,390,390,
+390,390,390,390,391,391,392,391,391,391,391,391,391,391,392,392,
+392,392,392,392,392,392,391,392,392,391,391,391,391,391,391,391,
+391,391,391,391,393,393,393,394,393,393,393,395,390,391,120,120,
+396,396,396,396,396,396,396,396,396,396,120,120,120,120,120,120,
+397,397,397,397,397,397,397,397,397,397,120,120,120,120,120,120,
/* block 46 */
-394,394,395,395,394,395,396,394,394,394,394,397,397,397,398,120,
-399,399,399,399,399,399,399,399,399,399,120,120,120,120,120,120,
-400,400,400,400,400,400,400,400,400,400,400,400,400,400,400,400,
-400,400,400,400,400,400,400,400,400,400,400,400,400,400,400,400,
-400,400,400,401,400,400,400,400,400,400,400,400,400,400,400,400,
-400,400,400,400,400,400,400,400,400,400,400,400,400,400,400,400,
-400,400,400,400,400,400,400,400,400,400,400,400,400,400,400,400,
-400,400,400,400,400,400,400,400,400,120,120,120,120,120,120,120,
+398,398,399,399,398,399,400,398,398,398,398,401,401,401,402,401,
+403,403,403,403,403,403,403,403,403,403,120,120,120,120,120,120,
+404,404,404,404,404,404,404,404,404,404,404,404,404,404,404,404,
+404,404,404,404,404,404,404,404,404,404,404,404,404,404,404,404,
+404,404,404,405,404,404,404,404,404,404,404,404,404,404,404,404,
+404,404,404,404,404,404,404,404,404,404,404,404,404,404,404,404,
+404,404,404,404,404,404,404,404,404,404,404,404,404,404,404,404,
+404,404,404,404,404,404,404,404,404,120,120,120,120,120,120,120,
/* block 47 */
-400,400,400,400,400,397,397,400,400,400,400,400,400,400,400,400,
-400,400,400,400,400,400,400,400,400,400,400,400,400,400,400,400,
-400,400,400,400,400,400,400,400,400,397,400,120,120,120,120,120,
-368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
-368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
-368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
-368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
-368,368,368,368,368,368,120,120,120,120,120,120,120,120,120,120,
+404,404,404,404,404,401,401,404,404,404,404,404,404,404,404,404,
+404,404,404,404,404,404,404,404,404,404,404,404,404,404,404,404,
+404,404,404,404,404,404,404,404,404,401,404,120,120,120,120,120,
+370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,
+370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,
+370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,
+370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,
+370,370,370,370,370,370,120,120,120,120,120,120,120,120,120,120,
/* block 48 */
-402,402,402,402,402,402,402,402,402,402,402,402,402,402,402,402,
-402,402,402,402,402,402,402,402,402,402,402,402,402,402,402,120,
-403,403,403,404,404,404,404,403,403,404,404,404,120,120,120,120,
-404,404,403,404,404,404,404,404,404,403,403,403,120,120,120,120,
-405,120,120,120,406,406,407,407,407,407,407,407,407,407,407,407,
-408,408,408,408,408,408,408,408,408,408,408,408,408,408,408,408,
-408,408,408,408,408,408,408,408,408,408,408,408,408,408,120,120,
-408,408,408,408,408,120,120,120,120,120,120,120,120,120,120,120,
+406,406,406,406,406,406,406,406,406,406,406,406,406,406,406,406,
+406,406,406,406,406,406,406,406,406,406,406,406,406,406,406,120,
+407,407,407,408,408,408,408,407,407,408,408,408,120,120,120,120,
+408,408,407,408,408,408,408,408,408,407,407,407,120,120,120,120,
+409,120,120,120,410,410,411,411,411,411,411,411,411,411,411,411,
+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,120,120,
+412,412,412,412,412,120,120,120,120,120,120,120,120,120,120,120,
/* block 49 */
-409,409,409,409,409,409,409,409,409,409,409,409,409,409,409,409,
-409,409,409,409,409,409,409,409,409,409,409,409,409,409,409,409,
-409,409,409,409,409,409,409,409,409,409,409,409,120,120,120,120,
-409,409,409,409,409,409,409,409,409,409,409,409,409,409,409,409,
-409,409,409,409,409,409,409,409,409,409,120,120,120,120,120,120,
-410,410,410,410,410,410,410,410,410,410,411,120,120,120,412,412,
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,413,413,413,120,120,120,120,
+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,120,120,120,120,120,120,
+414,414,414,414,414,414,414,414,414,414,415,120,120,120,416,416,
+417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,
+417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,417,
/* block 50 */
-414,414,414,414,414,414,414,414,414,414,414,414,414,414,414,414,
-414,414,414,414,414,414,414,415,415,416,416,415,120,120,417,417,
-418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,
-418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,
418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,
-418,418,418,418,418,419,420,419,420,420,420,420,420,420,420,120,
-420,421,420,421,421,420,420,420,420,420,420,420,420,419,419,419,
-419,419,419,420,420,420,420,420,420,420,420,420,420,120,120,420,
+418,418,418,418,418,418,418,419,419,420,420,419,120,120,421,421,
+422,422,422,422,422,422,422,422,422,422,422,422,422,422,422,422,
+422,422,422,422,422,422,422,422,422,422,422,422,422,422,422,422,
+422,422,422,422,422,422,422,422,422,422,422,422,422,422,422,422,
+422,422,422,422,422,423,424,423,424,424,424,424,424,424,424,120,
+424,425,424,425,425,424,424,424,424,424,424,424,424,423,423,423,
+423,423,423,424,424,424,424,424,424,424,424,424,424,120,120,424,
/* block 51 */
-422,422,422,422,422,422,422,422,422,422,120,120,120,120,120,120,
-422,422,422,422,422,422,422,422,422,422,120,120,120,120,120,120,
-423,423,423,423,423,423,423,424,423,423,423,423,423,423,120,120,
-113,113,113,113,113,113,113,113,113,113,113,113,113,113,425,113,
-113,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+426,426,426,426,426,426,426,426,426,426,120,120,120,120,120,120,
+426,426,426,426,426,426,426,426,426,426,120,120,120,120,120,120,
+427,427,427,427,427,427,427,428,427,427,427,427,427,427,120,120,
+113,113,113,113,113,113,113,113,113,113,113,113,113,113,429,113,
+113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
/* block 52 */
-426,426,426,426,427,428,428,428,428,428,428,428,428,428,428,428,
-428,428,428,428,428,428,428,428,428,428,428,428,428,428,428,428,
-428,428,428,428,428,428,428,428,428,428,428,428,428,428,428,428,
-428,428,428,428,426,429,426,426,426,426,426,427,426,427,427,427,
-427,427,426,427,427,428,428,428,428,428,428,428,120,120,120,120,
-430,430,430,430,430,430,430,430,430,430,431,431,431,431,431,431,
-431,432,432,432,432,432,432,432,432,432,432,426,426,426,426,426,
-426,426,426,426,432,432,432,432,432,432,432,432,432,120,120,120,
+430,430,430,430,431,432,432,432,432,432,432,432,432,432,432,432,
+432,432,432,432,432,432,432,432,432,432,432,432,432,432,432,432,
+432,432,432,432,432,432,432,432,432,432,432,432,432,432,432,432,
+432,432,432,432,430,433,430,430,430,430,430,431,430,431,431,431,
+431,431,430,431,431,432,432,432,432,432,432,432,432,120,120,120,
+434,434,434,434,434,434,434,434,434,434,435,435,435,435,435,435,
+435,436,436,436,436,436,436,436,436,436,436,430,430,430,430,430,
+430,430,430,430,436,436,436,436,436,436,436,436,436,435,435,120,
/* block 53 */
-433,433,434,435,435,435,435,435,435,435,435,435,435,435,435,435,
-435,435,435,435,435,435,435,435,435,435,435,435,435,435,435,435,
-435,434,433,433,433,433,434,434,433,433,434,433,433,433,435,435,
-436,436,436,436,436,436,436,436,436,436,435,435,435,435,435,435,
-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,438,439,438,438,439,439,439,438,439,438,
-438,438,439,439,120,120,120,120,120,120,120,120,440,440,440,440,
-
-/* block 54 */
+437,437,438,439,439,439,439,439,439,439,439,439,439,439,439,439,
+439,439,439,439,439,439,439,439,439,439,439,439,439,439,439,439,
+439,438,437,437,437,437,438,438,437,437,438,437,437,437,439,439,
+440,440,440,440,440,440,440,440,440,440,439,439,439,439,439,439,
441,441,441,441,441,441,441,441,441,441,441,441,441,441,441,441,
441,441,441,441,441,441,441,441,441,441,441,441,441,441,441,441,
-441,441,441,441,442,442,442,442,442,442,442,442,443,443,443,443,
-443,443,443,443,442,442,443,443,120,120,120,444,444,444,444,444,
-445,445,445,445,445,445,445,445,445,445,120,120,120,441,441,441,
-446,446,446,446,446,446,446,446,446,446,447,447,447,447,447,447,
-447,447,447,447,447,447,447,447,447,447,447,447,447,447,447,447,
-447,447,447,447,447,447,447,447,448,448,448,448,448,448,449,449,
+441,441,441,441,441,441,442,443,442,442,443,443,443,442,443,442,
+442,442,443,443,120,120,120,120,120,120,120,120,444,444,444,444,
+
+/* block 54 */
+445,445,445,445,445,445,445,445,445,445,445,445,445,445,445,445,
+445,445,445,445,445,445,445,445,445,445,445,445,445,445,445,445,
+445,445,445,445,446,446,446,446,446,446,446,446,447,447,447,447,
+447,447,447,447,446,446,447,447,120,120,120,448,448,448,448,448,
+449,449,449,449,449,449,449,449,449,449,120,120,120,445,445,445,
+450,450,450,450,450,450,450,450,450,450,451,451,451,451,451,451,
+451,451,451,451,451,451,451,451,451,451,451,451,451,451,451,451,
+451,451,451,451,451,451,451,451,452,452,452,452,452,452,453,453,
/* block 55 */
-450,451,452,453,454,455,456,457,458,120,120,120,120,120,120,120,
-459,459,459,459,459,459,459,459,459,459,459,459,459,459,459,459,
-459,459,459,459,459,459,459,459,459,459,459,459,459,459,459,459,
-459,459,459,459,459,459,459,459,459,459,459,120,120,459,459,459,
-460,460,460,460,460,460,460,460,120,120,120,120,120,120,120,120,
-461,462,461,463,462,464,464,465,464,465,466,462,465,465,462,462,
-465,467,462,462,462,462,462,462,462,468,469,470,470,464,470,470,
-470,470,471,472,473,469,469,474,475,475,476,120,120,120,120,120,
+454,455,456,457,458,459,460,461,462,120,120,120,120,120,120,120,
+463,463,463,463,463,463,463,463,463,463,463,463,463,463,463,463,
+463,463,463,463,463,463,463,463,463,463,463,463,463,463,463,463,
+463,463,463,463,463,463,463,463,463,463,463,120,120,463,463,463,
+464,464,464,464,464,464,464,464,120,120,120,120,120,120,120,120,
+465,466,465,467,466,468,468,469,468,469,470,466,469,469,466,466,
+469,471,466,466,466,466,466,466,466,472,473,474,474,468,474,474,
+474,474,475,476,477,473,473,478,479,479,480,120,120,120,120,120,
/* block 56 */
35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35,128,128,128,128,128,477,110,110,110,110,
+ 35, 35, 35, 35, 35, 35,128,128,128,128,128,481,110,110,110,110,
110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
110,110,110,110,110,110,110,110,110,110,110,110,110,121,121,121,
121,121,110,110,110,110,121,121,121,121,121, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35,478,479, 35, 35, 35,480, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35,482,483, 35, 35, 35,484, 35, 35,
/* block 57 */
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,481, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,485, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,110,110,110,110,110,
110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,121,
114,114,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
-113,113,113,113,113,113,113,113,482,113,120,113,113,113,113,113,
+113,113,113,113,113,113,113,113,486,113,487,113,113,113,113,113,
/* block 58 */
32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
@@ -2305,12 +2331,12 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
-483,484, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+488,489, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
/* block 59 */
32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
- 32, 33, 32, 33, 32, 33, 35, 35, 35, 35, 35,485, 35, 35,486, 35,
+ 32, 33, 32, 33, 32, 33, 35, 35, 35, 35, 35,490, 35, 35,491, 35,
32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
@@ -2319,33 +2345,33 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
/* block 60 */
-487,487,487,487,487,487,487,487,488,488,488,488,488,488,488,488,
-487,487,487,487,487,487,120,120,488,488,488,488,488,488,120,120,
-487,487,487,487,487,487,487,487,488,488,488,488,488,488,488,488,
-487,487,487,487,487,487,487,487,488,488,488,488,488,488,488,488,
-487,487,487,487,487,487,120,120,488,488,488,488,488,488,120,120,
-128,487,128,487,128,487,128,487,120,488,120,488,120,488,120,488,
-487,487,487,487,487,487,487,487,488,488,488,488,488,488,488,488,
-489,489,490,490,490,490,491,491,492,492,493,493,494,494,120,120,
+492,492,492,492,492,492,492,492,493,493,493,493,493,493,493,493,
+492,492,492,492,492,492,120,120,493,493,493,493,493,493,120,120,
+492,492,492,492,492,492,492,492,493,493,493,493,493,493,493,493,
+492,492,492,492,492,492,492,492,493,493,493,493,493,493,493,493,
+492,492,492,492,492,492,120,120,493,493,493,493,493,493,120,120,
+128,492,128,492,128,492,128,492,120,493,120,493,120,493,120,493,
+492,492,492,492,492,492,492,492,493,493,493,493,493,493,493,493,
+494,494,495,495,495,495,496,496,497,497,498,498,499,499,120,120,
/* block 61 */
-487,487,487,487,487,487,487,487,495,495,495,495,495,495,495,495,
-487,487,487,487,487,487,487,487,495,495,495,495,495,495,495,495,
-487,487,487,487,487,487,487,487,495,495,495,495,495,495,495,495,
-487,487,128,496,128,120,128,128,488,488,497,497,498,119,499,119,
-119,119,128,496,128,120,128,128,500,500,500,500,498,119,119,119,
-487,487,128,128,120,120,128,128,488,488,501,501,120,119,119,119,
-487,487,128,128,128,169,128,128,488,488,502,502,174,119,119,119,
-120,120,128,496,128,120,128,128,503,503,504,504,498,119,119,120,
+492,492,492,492,492,492,492,492,500,500,500,500,500,500,500,500,
+492,492,492,492,492,492,492,492,500,500,500,500,500,500,500,500,
+492,492,492,492,492,492,492,492,500,500,500,500,500,500,500,500,
+492,492,128,501,128,120,128,128,493,493,502,502,503,119,504,119,
+119,119,128,501,128,120,128,128,505,505,505,505,503,119,119,119,
+492,492,128,128,120,120,128,128,493,493,506,506,120,119,119,119,
+492,492,128,128,128,169,128,128,493,493,507,507,174,119,119,119,
+120,120,128,501,128,120,128,128,508,508,509,509,503,119,119,120,
/* block 62 */
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 24,505,506, 24, 24,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 24,510,511, 24, 24,
10, 10, 10, 10, 10, 10, 5, 5, 23, 27, 7, 23, 23, 27, 7, 23,
- 5, 5, 5, 5, 5, 5, 5, 5,507,508, 24, 24, 24, 24, 24,509,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 23, 27, 5,510, 5, 5, 16,
- 16, 5, 5, 5, 9, 7, 8, 5, 5,510, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,512,513, 24, 24, 24, 24, 24,514,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 23, 27, 5,515, 5, 5, 16,
+ 16, 5, 5, 5, 9, 7, 8, 5, 5,515, 5, 5, 5, 5, 5, 5,
5, 5, 9, 5, 16, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4,
- 24, 24, 24, 24, 24,511, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24,516, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
25,110,120,120, 25, 25, 25, 25, 25, 25, 9, 9, 9, 7, 8,110,
/* block 63 */
@@ -2353,24 +2379,24 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
110,110,110,110,110,110,110,110,110,110,110,110,110,120,120,120,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
-120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-113,113,113,113,113,113,113,113,113,113,113,113,113,425,425,425,
-425,113,425,425,425,113,113,113,113,113,113,113,113,113,113,113,
-512,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+ 6,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+113,113,113,113,113,113,113,113,113,113,113,113,113,429,429,429,
+429,113,429,429,429,113,113,113,113,113,113,113,113,113,113,113,
+517,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
/* block 64 */
- 20, 20,513, 20, 20, 20, 20,513, 20, 20,514,513,513,513,514,514,
-513,513,513,514, 20,513, 20, 20, 9,513,513,513,513,513, 20, 20,
- 20, 20, 21, 20,513, 20,515, 20,513, 20,516,517,513,513, 20,514,
-513,513,518,513,514,519,519,519,519,520, 20, 20,514,514,513,513,
- 9, 9, 9, 9, 9,513,514,514,514,514, 20, 9, 20, 20,521, 20,
+ 20, 20,518, 20, 20, 20, 20,518, 20, 20,519,518,518,518,519,519,
+518,518,518,519, 20,518, 20, 20, 9,518,518,518,518,518, 20, 20,
+ 20, 20, 21, 20,518, 20,520, 20,518, 20,521,522,518,518, 20,519,
+518,518,523,518,519,524,524,524,524,525, 20, 20,519,519,518,518,
+ 9, 9, 9, 9, 9,518,519,519,519,519, 20, 9, 20, 20,526, 20,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
-522,522,522,522,522,522,522,522,522,522,522,522,522,522,522,522,
-523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+527,527,527,527,527,527,527,527,527,527,527,527,527,527,527,527,
+528,528,528,528,528,528,528,528,528,528,528,528,528,528,528,528,
/* block 65 */
-524,524,524, 32, 33,524,524,524,524, 25, 20, 20,120,120,120,120,
- 9, 9, 9, 9,525, 21, 21, 21, 21, 21, 9, 9, 20, 20, 20, 20,
+529,529,529, 32, 33,529,529,529,529, 25, 20, 20,120,120,120,120,
+ 9, 9, 9, 9,530, 21, 21, 21, 21, 21, 9, 9, 20, 20, 20, 20,
9, 20, 20, 9, 20, 20, 9, 20, 20, 21, 21, 20, 20, 20, 9, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 9, 9,
@@ -2422,10 +2448,10 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
- 20, 20, 20, 20, 20, 20,526,526,526,526,526,526,526,526,526,526,
-526,526,527,526,526,526,526,526,526,526,526,526,526,526,526,526,
-528,528,528,528,528,528,528,528,528,528,528,528,528,528,528,528,
-528,528,528,528,528,528,528,528,528,528, 25, 25, 25, 25, 25, 25,
+ 20, 20, 20, 20, 20, 20,531,531,531,531,531,531,531,531,531,531,
+531,531,532,531,531,531,531,531,531,531,531,531,531,531,531,531,
+533,533,533,533,533,533,533,533,533,533,533,533,533,533,533,533,
+533,533,533,533,533,533,533,533,533,533, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
/* block 71 */
@@ -2446,7 +2472,7 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
21, 9, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
- 20, 20, 20, 20, 20, 20, 20, 20, 9, 9, 9,525,525,525,525, 9,
+ 20, 20, 20, 20, 20, 20, 20, 20, 9, 9, 9,530,530,530,530, 9,
/* block 73 */
21, 21, 21, 21, 21, 21, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21,
@@ -2455,7 +2481,7 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
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, 21, 21, 21, 21,525,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,530,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
/* block 74 */
@@ -2489,20 +2515,20 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
/* block 77 */
-529,529,529,529,529,529,529,529,529,529,529,529,529,529,529,529,
-529,529,529,529,529,529,529,529,529,529,529,529,529,529,529,529,
-529,529,529,529,529,529,529,529,529,529,529,529,529,529,529,529,
-529,529,529,529,529,529,529,529,529,529,529,529,529,529,529,529,
-529,529,529,529,529,529,529,529,529,529,529,529,529,529,529,529,
-529,529,529,529,529,529,529,529,529,529,529,529,529,529,529,529,
-529,529,529,529,529,529,529,529,529,529,529,529,529,529,529,529,
-529,529,529,529,529,529,529,529,529,529,529,529,529,529,529,529,
+534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,
+534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,
+534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,
+534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,
+534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,
+534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,
+534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,
+534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,
/* block 78 */
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,525,525, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9,530,530, 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,
@@ -2539,14 +2565,14 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
/* block 82 */
-530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,
-530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,
-530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,120,
-531,531,531,531,531,531,531,531,531,531,531,531,531,531,531,531,
-531,531,531,531,531,531,531,531,531,531,531,531,531,531,531,531,
-531,531,531,531,531,531,531,531,531,531,531,531,531,531,531,120,
- 32, 33,532,533,534,535,536, 32, 33, 32, 33, 32, 33,537,538,539,
-540, 35, 32, 33, 35, 32, 33, 35, 35, 35, 35, 35,110,110,541,541,
+535,535,535,535,535,535,535,535,535,535,535,535,535,535,535,535,
+535,535,535,535,535,535,535,535,535,535,535,535,535,535,535,535,
+535,535,535,535,535,535,535,535,535,535,535,535,535,535,535,535,
+536,536,536,536,536,536,536,536,536,536,536,536,536,536,536,536,
+536,536,536,536,536,536,536,536,536,536,536,536,536,536,536,536,
+536,536,536,536,536,536,536,536,536,536,536,536,536,536,536,536,
+ 32, 33,537,538,539,540,541, 32, 33, 32, 33, 32, 33,542,543,544,
+545, 35, 32, 33, 35, 32, 33, 35, 35, 35, 35, 35,110,110,546,546,
/* block 83 */
165,166,165,166,165,166,165,166,165,166,165,166,165,166,165,166,
@@ -2555,138 +2581,138 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
165,166,165,166,165,166,165,166,165,166,165,166,165,166,165,166,
165,166,165,166,165,166,165,166,165,166,165,166,165,166,165,166,
165,166,165,166,165,166,165,166,165,166,165,166,165,166,165,166,
-165,166,165,166,542,543,543,543,543,543,543,165,166,165,166,544,
-544,544,165,166,120,120,120,120,120,545,545,545,545,546,545,545,
+165,166,165,166,547,548,548,548,548,548,548,165,166,165,166,549,
+549,549,165,166,120,120,120,120,120,550,550,550,550,551,550,550,
/* block 84 */
-547,547,547,547,547,547,547,547,547,547,547,547,547,547,547,547,
-547,547,547,547,547,547,547,547,547,547,547,547,547,547,547,547,
-547,547,547,547,547,547,120,547,120,120,120,120,120,547,120,120,
-548,548,548,548,548,548,548,548,548,548,548,548,548,548,548,548,
-548,548,548,548,548,548,548,548,548,548,548,548,548,548,548,548,
-548,548,548,548,548,548,548,548,548,548,548,548,548,548,548,548,
-548,548,548,548,548,548,548,548,120,120,120,120,120,120,120,549,
-550,120,120,120,120,120,120,120,120,120,120,120,120,120,120,551,
-
-/* block 85 */
-359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
-359,359,359,359,359,359,359,120,120,120,120,120,120,120,120,120,
-359,359,359,359,359,359,359,120,359,359,359,359,359,359,359,120,
-359,359,359,359,359,359,359,120,359,359,359,359,359,359,359,120,
-359,359,359,359,359,359,359,120,359,359,359,359,359,359,359,120,
-359,359,359,359,359,359,359,120,359,359,359,359,359,359,359,120,
552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,
552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,
+552,552,552,552,552,552,120,552,120,120,120,120,120,552,120,120,
+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,553,553,553,553,
+553,553,553,553,553,553,553,553,120,120,120,120,120,120,120,554,
+555,120,120,120,120,120,120,120,120,120,120,120,120,120,120,556,
+
+/* block 85 */
+361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,
+361,361,361,361,361,361,361,120,120,120,120,120,120,120,120,120,
+361,361,361,361,361,361,361,120,361,361,361,361,361,361,361,120,
+361,361,361,361,361,361,361,120,361,361,361,361,361,361,361,120,
+361,361,361,361,361,361,361,120,361,361,361,361,361,361,361,120,
+361,361,361,361,361,361,361,120,361,361,361,361,361,361,361,120,
+557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,
+557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,
/* block 86 */
5, 5, 23, 27, 23, 27, 5, 5, 5, 23, 27, 5, 23, 27, 5, 5,
5, 5, 5, 5, 5, 5, 5, 10, 5, 5, 10, 5, 23, 27, 5, 5,
23, 27, 7, 8, 7, 8, 7, 8, 7, 8, 5, 5, 5, 5, 5,111,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 10, 10, 5, 5, 5, 5,
- 10, 5, 7,553, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 20, 20, 5,120,120,120,120,120,120,120,120,120,120,120,120,120,
+ 10, 5, 7,558, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 20, 20, 5, 5, 5, 7, 8, 7, 8, 7, 8, 7, 8, 10,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
/* block 87 */
-554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
-554,554,554,554,554,554,554,554,554,554,120,554,554,554,554,554,
-554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
-554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
-554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
-554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
-554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
-554,554,554,554,120,120,120,120,120,120,120,120,120,120,120,120,
+559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,
+559,559,559,559,559,559,559,559,559,559,120,559,559,559,559,559,
+559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,
+559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,
+559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,
+559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,
+559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,
+559,559,559,559,120,120,120,120,120,120,120,120,120,120,120,120,
/* block 88 */
-554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
-554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
-554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
-554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
-554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
-554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
-554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
-554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
+559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,
+559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,
+559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,
+559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,
+559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,
+559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,
+559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,
+559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,
/* block 89 */
-554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
-554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
-554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
-554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
-554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
-554,554,554,554,554,554,120,120,120,120,120,120,120,120,120,120,
+559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,
+559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,
+559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,
+559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,
+559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,
+559,559,559,559,559,559,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,120,120,120,120,
/* block 90 */
- 4,555,555,556, 20,557,558,559,560,561,560,561,560,561,560,561,
-560,561, 20,562,560,561,560,561,560,561,560,561,563,564,565,565,
- 20,559,559,559,559,559,559,559,559,559,566,566,566,566,567,567,
-568,569,569,569,569,569, 20,562,559,559,559,557,570,571,572,572,
-120,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
-573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
-573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
-573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
-
-/* block 91 */
-573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
-573,573,573,573,573,573,573,120,120,574,574,575,575,576,576,573,
-577,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
+ 4,560,560,561, 20,562,563,564,565,566,565,566,565,566,565,566,
+565,566, 20,567,565,566,565,566,565,566,565,566,568,569,570,570,
+ 20,564,564,564,564,564,564,564,564,564,571,571,571,571,572,572,
+573,574,574,574,574,574, 20,567,564,564,564,562,575,576,577,577,
+120,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
+
+/* block 91 */
578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
-578,578,578,578,578,578,578,578,578,578,578,555,569,579,579,578,
+578,578,578,578,578,578,578,120,120,579,579,580,580,581,581,578,
+582,583,583,583,583,583,583,583,583,583,583,583,583,583,583,583,
+583,583,583,583,583,583,583,583,583,583,583,583,583,583,583,583,
+583,583,583,583,583,583,583,583,583,583,583,583,583,583,583,583,
+583,583,583,583,583,583,583,583,583,583,583,583,583,583,583,583,
+583,583,583,583,583,583,583,583,583,583,583,583,583,583,583,583,
+583,583,583,583,583,583,583,583,583,583,583,560,574,584,584,583,
/* block 92 */
-120,120,120,120,120,580,580,580,580,580,580,580,580,580,580,580,
-580,580,580,580,580,580,580,580,580,580,580,580,580,580,580,580,
-580,580,580,580,580,580,580,580,580,580,580,580,580,580,580,580,
-120,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,
-581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,
-581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,
-581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,
-581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,
+120,120,120,120,120,585,585,585,585,585,585,585,585,585,585,585,
+585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,
+585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,
+120,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
/* block 93 */
-581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,120,
-572,572,582,582,582,582,572,572,572,572,572,572,572,572,572,572,
-580,580,580,580,580,580,580,580,580,580,580,580,580,580,580,580,
-580,580,580,580,580,580,580,580,580,580,580,580,580,580,580,580,
-572,572,572,572,572,572,572,572,572,572,572,572,572,572,572,572,
-572,572,572,572,572,572,572,572,572,572,572,572,572,572,572,572,
-572,572,572,572,120,120,120,120,120,120,120,120,120,120,120,120,
-578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,120,
+577,577,587,587,587,587,577,577,577,577,577,577,577,577,577,577,
+585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,
+585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,
+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,120,120,120,120,120,120,120,120,120,120,120,120,
+583,583,583,583,583,583,583,583,583,583,583,583,583,583,583,583,
/* block 94 */
-583,583,583,583,583,583,583,583,583,583,583,583,583,583,583,583,
-583,583,583,583,583,583,583,583,583,583,583,583,583,583,583,120,
-582,582,582,582,582,582,582,582,582,582,572,572,572,572,572,572,
-572,572,572,572,572,572,572,572,572,572,572,572,572,572,572,572,
-572,572,572,572,572,572,572,572, 25, 25, 25, 25, 25, 25, 25, 25,
+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,588,120,
+587,587,587,587,587,587,587,587,587,587,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, 25, 25, 25, 25, 25, 25, 25, 25,
20, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
-583,583,583,583,583,583,583,583,583,583,583,583,583,583,583,583,
-583,583,583,583,583,583,583,583,583,583,583,583,583,583,583, 20,
+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,588, 20,
/* block 95 */
-582,582,582,582,582,582,582,582,582,582,572,572,572,572,572,572,
-572,572,572,572,572,572,572,584,572,584,572,572,572,572,572,572,
-572,572,572,572,572,572,572,572,572,572,572,572,572,572,572,572,
-572, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
-572,572,572,572,572,572,572,572,572,572,572,572, 20, 20, 20, 20,
-585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,
-585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,
-585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,572,
+587,587,587,587,587,587,587,587,587,587,577,577,577,577,577,577,
+577,577,577,577,577,577,577,589,577,589,577,577,577,577,577,577,
+577,577,577,577,577,577,577,577,577,577,577,577,577,577,577,577,
+577, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+577,577,577,577,577,577,577,577,577,577,577,577, 20, 20, 20, 20,
+590,590,590,590,590,590,590,590,590,590,590,590,590,590,590,590,
+590,590,590,590,590,590,590,590,590,590,590,590,590,590,590,590,
+590,590,590,590,590,590,590,590,590,590,590,590,590,590,590,577,
/* block 96 */
-585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,
-585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,
-585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,
-585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,
-585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,
-585,585,585,585,585,585,585,585,572,572,572,572,572,572,572,572,
-572,572,572,572,572,572,572,572,572,572,572,572,572,572,572,572,
-572, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,572,572,572,572,572,
+590,590,590,590,590,590,590,590,590,590,590,590,590,590,590,590,
+590,590,590,590,590,590,590,590,590,590,590,590,590,590,590,590,
+590,590,590,590,590,590,590,590,590,590,590,590,590,590,590,590,
+590,590,590,590,590,590,590,590,590,590,590,590,590,590,590,590,
+590,590,590,590,590,590,590,590,590,590,590,590,590,590,590,590,
+590,590,590,590,590,590,590,590,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, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,577,577,577,577,577,
/* block 97 */
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
@@ -2695,450 +2721,440 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
-572,572,572,572,572,572,572,572,572,572,572,572,572,572,572,572,
-572,572,572,572,572,572,572,572,572,572,572,572,572,572,572, 20,
+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, 20,
/* block 98 */
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+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,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,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,591,591,591,591,591,591,591,591,591,591,591,591,591,591,
/* block 99 */
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+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,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,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
/* block 100 */
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,120,120,120,
+592,592,592,592,592,592,592,592,592,592,592,592,592,592,592,592,
+592,592,592,592,592,593,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,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,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,
/* block 101 */
-587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,
-587,587,587,587,587,588,587,587,587,587,587,587,587,587,587,587,
-587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,
-587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,
-587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,
-587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,
-587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,
-587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,
+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,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,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,592,592,592,592,592,592,592,592,592,592,592,592,592,592,
/* block 102 */
-587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,
-587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,
-587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,
-587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,
-587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,
-587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,
-587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,
-587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,
+592,592,592,592,592,592,592,592,592,592,592,592,592,120,120,120,
+594,594,594,594,594,594,594,594,594,594,594,594,594,594,594,594,
+594,594,594,594,594,594,594,594,594,594,594,594,594,594,594,594,
+594,594,594,594,594,594,594,594,594,594,594,594,594,594,594,594,
+594,594,594,594,594,594,594,120,120,120,120,120,120,120,120,120,
+595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+595,595,595,595,595,595,595,595,596,596,596,596,596,596,597,597,
/* block 103 */
-587,587,587,587,587,587,587,587,587,587,587,587,587,120,120,120,
-589,589,589,589,589,589,589,589,589,589,589,589,589,589,589,589,
-589,589,589,589,589,589,589,589,589,589,589,589,589,589,589,589,
-589,589,589,589,589,589,589,589,589,589,589,589,589,589,589,589,
-589,589,589,589,589,589,589,120,120,120,120,120,120,120,120,120,
-590,590,590,590,590,590,590,590,590,590,590,590,590,590,590,590,
-590,590,590,590,590,590,590,590,590,590,590,590,590,590,590,590,
-590,590,590,590,590,590,590,590,591,591,591,591,591,591,592,592,
+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,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,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,598,598,598,598,
+598,598,598,598,598,598,598,598,598,598,598,598,598,598,598,598,
/* block 104 */
-593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,
-593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,
-593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,
-593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,
-593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,
-593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,
-593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,
-593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,
-
-/* block 105 */
-593,593,593,593,593,593,593,593,593,593,593,593,594,595,595,595,
-593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,
-596,596,596,596,596,596,596,596,596,596,593,593,120,120,120,120,
+598,598,598,598,598,598,598,598,598,598,598,598,599,600,600,600,
+598,598,598,598,598,598,598,598,598,598,598,598,598,598,598,598,
+601,601,601,601,601,601,601,601,601,601,598,598,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-192,193,192,193,192,193,192,193,192,193,597,598,192,193,192,193,
+192,193,192,193,192,193,192,193,192,193,602,603,192,193,192,193,
192,193,192,193,192,193,192,193,192,193,192,193,192,193,192,193,
-192,193,192,193,192,193,192,193,192,193,192,193,192,193,599,198,
-200,200,200,600,552,552,552,552,552,552,552,552,552,552,600,478,
+192,193,192,193,192,193,192,193,192,193,192,193,192,193,604,198,
+200,200,200,605,557,557,557,557,557,557,557,557,557,557,605,482,
-/* block 106 */
+/* block 105 */
192,193,192,193,192,193,192,193,192,193,192,193,192,193,192,193,
-192,193,192,193,192,193,192,193,192,193,192,193,478,478,552,552,
-601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
-601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
-601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
-601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
-601,601,601,601,601,601,602,602,602,602,602,602,602,602,602,602,
-603,603,604,604,604,604,604,604,120,120,120,120,120,120,120,120,
+192,193,192,193,192,193,192,193,192,193,192,193,482,482,557,557,
+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,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,606,606,606,606,
+606,606,606,606,606,606,607,607,607,607,607,607,607,607,607,607,
+608,608,609,609,609,609,609,609,120,120,120,120,120,120,120,120,
-/* block 107 */
-605,605,605,605,605,605,605,605, 15, 15, 15, 15, 15, 15, 15, 15,
+/* block 106 */
+610,610,610,610,610,610,610,610, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15,111,111,111,111,111,111,111,111,111,
15, 15, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
35, 35, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
-110, 35, 35, 35, 35, 35, 35, 35, 35, 32, 33, 32, 33,606, 32, 33,
+110, 35, 35, 35, 35, 35, 35, 35, 35, 32, 33, 32, 33,611, 32, 33,
-/* block 108 */
- 32, 33, 32, 33, 32, 33, 32, 33,111, 15, 15, 32, 33,607, 35, 22,
- 32, 33, 32, 33,608, 35, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
- 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,609,610,611,612,609, 35,
-613,614,615,616, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
-120,120, 32, 33,617,618,619, 32, 33, 32, 33,120,120,120,120,120,
-120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+/* block 107 */
+ 32, 33, 32, 33, 32, 33, 32, 33,111, 15, 15, 32, 33,612, 35, 22,
+ 32, 33, 32, 33,613, 35, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+ 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,614,615,616,617,614, 35,
+618,619,620,621, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+ 32, 33, 32, 33,622,623,624, 32, 33, 32, 33,120,120,120,120,120,
+ 32, 33,120, 35,120, 35, 32, 33, 32, 33,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-120,120,120,120,120, 32, 33, 22,110,110, 35, 22, 22, 22, 22, 22,
+120,120,110,110,110, 32, 33, 22,110,110, 35, 22, 22, 22, 22, 22,
+
+/* block 108 */
+625,625,626,625,625,625,626,625,625,625,625,626,625,625,625,625,
+625,625,625,625,625,625,625,625,625,625,625,625,625,625,625,625,
+625,625,625,627,627,626,626,627,628,628,628,628,626,120,120,120,
+629,629,629,630,630,630,631,631,632,631,120,120,120,120,120,120,
+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,633,633,633,633,633,633,633,633,633,633,633,633,633,633,633,
+633,633,633,633,634,634,634,634,120,120,120,120,120,120,120,120,
/* block 109 */
-620,620,621,620,620,620,621,620,620,620,620,621,620,620,620,620,
-620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,
-620,620,620,622,622,621,621,622,623,623,623,623,621,120,120,120,
-624,624,624,625,625,625,626,626,627,626,120,120,120,120,120,120,
-628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,
-628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,
-628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,
-628,628,628,628,629,629,629,629,120,120,120,120,120,120,120,120,
+635,635,636,636,636,636,636,636,636,636,636,636,636,636,636,636,
+636,636,636,636,636,636,636,636,636,636,636,636,636,636,636,636,
+636,636,636,636,636,636,636,636,636,636,636,636,636,636,636,636,
+636,636,636,636,635,635,635,635,635,635,635,635,635,635,635,635,
+635,635,635,635,637,637,120,120,120,120,120,120,120,120,638,638,
+639,639,639,639,639,639,639,639,639,639,120,120,120,120,120,120,
+253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,
+253,640,255,641,255,255,255,255,261,261,261,255,261,255,255,253,
/* block 110 */
-630,630,631,631,631,631,631,631,631,631,631,631,631,631,631,631,
-631,631,631,631,631,631,631,631,631,631,631,631,631,631,631,631,
-631,631,631,631,631,631,631,631,631,631,631,631,631,631,631,631,
-631,631,631,631,630,630,630,630,630,630,630,630,630,630,630,630,
-630,630,630,630,632,632,120,120,120,120,120,120,120,120,633,633,
-634,634,634,634,634,634,634,634,634,634,120,120,120,120,120,120,
-251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,
-251,635,253,636,253,253,253,253,259,259,259,253,259,253,253,251,
+642,642,642,642,642,642,642,642,642,642,643,643,643,643,643,643,
+643,643,643,643,643,643,643,643,643,643,643,643,643,643,643,643,
+643,643,643,643,643,643,644,644,644,644,644,644,644,644,645,646,
+647,647,647,647,647,647,647,647,647,647,647,647,647,647,647,647,
+647,647,647,647,647,647,647,648,648,648,648,648,648,648,648,648,
+648,648,649,649,120,120,120,120,120,120,120,120,120,120,120,650,
+358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,
+358,358,358,358,358,358,358,358,358,358,358,358,358,120,120,120,
/* block 111 */
-637,637,637,637,637,637,637,637,637,637,638,638,638,638,638,638,
-638,638,638,638,638,638,638,638,638,638,638,638,638,638,638,638,
-638,638,638,638,638,638,639,639,639,639,639,639,639,639,640,641,
-642,642,642,642,642,642,642,642,642,642,642,642,642,642,642,642,
-642,642,642,642,642,642,642,643,643,643,643,643,643,643,643,643,
-643,643,644,644,120,120,120,120,120,120,120,120,120,120,120,645,
-356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,
-356,356,356,356,356,356,356,356,356,356,356,356,356,120,120,120,
-
-/* block 112 */
-646,646,646,647,648,648,648,648,648,648,648,648,648,648,648,648,
-648,648,648,648,648,648,648,648,648,648,648,648,648,648,648,648,
-648,648,648,648,648,648,648,648,648,648,648,648,648,648,648,648,
-648,648,648,646,647,647,646,646,646,646,647,647,646,646,647,647,
-647,649,649,649,649,649,649,649,649,649,649,649,649,649,120,650,
-651,651,651,651,651,651,651,651,651,651,120,120,120,120,649,649,
-344,344,344,344,344,346,652,344,344,344,344,344,344,344,344,344,
-350,350,350,350,350,350,350,350,350,350,344,344,344,344,344,120,
-
-/* block 113 */
+651,651,651,652,653,653,653,653,653,653,653,653,653,653,653,653,
653,653,653,653,653,653,653,653,653,653,653,653,653,653,653,653,
653,653,653,653,653,653,653,653,653,653,653,653,653,653,653,653,
-653,653,653,653,653,653,653,653,653,654,654,654,654,654,654,655,
-655,654,654,655,655,654,654,120,120,120,120,120,120,120,120,120,
-653,653,653,654,653,653,653,653,653,653,653,653,654,655,120,120,
-656,656,656,656,656,656,656,656,656,656,120,120,657,657,657,657,
-344,344,344,344,344,344,344,344,344,344,344,344,344,344,344,344,
-652,344,344,344,344,344,344,351,351,351,344,345,346,345,344,344,
+653,653,653,651,652,652,651,651,651,651,652,652,651,651,652,652,
+652,654,654,654,654,654,654,654,654,654,654,654,654,654,120,655,
+656,656,656,656,656,656,656,656,656,656,120,120,120,120,654,654,
+346,346,346,346,346,348,657,346,346,346,346,346,346,346,346,346,
+352,352,352,352,352,352,352,352,352,352,346,346,346,346,346,120,
-/* block 114 */
-658,658,658,658,658,658,658,658,658,658,658,658,658,658,658,658,
+/* block 112 */
658,658,658,658,658,658,658,658,658,658,658,658,658,658,658,658,
658,658,658,658,658,658,658,658,658,658,658,658,658,658,658,658,
-659,658,659,659,659,658,658,659,659,658,658,658,658,658,659,659,
-658,659,658,120,120,120,120,120,120,120,120,120,120,120,120,120,
-120,120,120,120,120,120,120,120,120,120,120,658,658,660,661,661,
-662,662,662,662,662,662,662,662,662,662,662,663,664,664,663,663,
-665,665,662,666,666,663,664,120,120,120,120,120,120,120,120,120,
+658,658,658,658,658,658,658,658,658,659,659,659,659,659,659,660,
+660,659,659,660,660,659,659,120,120,120,120,120,120,120,120,120,
+658,658,658,659,658,658,658,658,658,658,658,658,659,660,120,120,
+661,661,661,661,661,661,661,661,661,661,120,120,662,662,662,662,
+346,346,346,346,346,346,346,346,346,346,346,346,346,346,346,346,
+657,346,346,346,346,346,346,353,353,353,346,347,348,347,346,346,
-/* block 115 */
-120,359,359,359,359,359,359,120,120,359,359,359,359,359,359,120,
-120,359,359,359,359,359,359,120,120,120,120,120,120,120,120,120,
-359,359,359,359,359,359,359,120,359,359,359,359,359,359,359,120,
+/* block 113 */
+663,663,663,663,663,663,663,663,663,663,663,663,663,663,663,663,
+663,663,663,663,663,663,663,663,663,663,663,663,663,663,663,663,
+663,663,663,663,663,663,663,663,663,663,663,663,663,663,663,663,
+664,663,664,664,664,663,663,664,664,663,663,663,663,663,664,664,
+663,664,663,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,663,663,665,666,666,
+667,667,667,667,667,667,667,667,667,667,667,668,669,669,668,668,
+670,670,667,671,671,668,669,120,120,120,120,120,120,120,120,120,
+
+/* block 114 */
+120,361,361,361,361,361,361,120,120,361,361,361,361,361,361,120,
+120,361,361,361,361,361,361,120,120,120,120,120,120,120,120,120,
+361,361,361,361,361,361,361,120,361,361,361,361,361,361,361,120,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35,667, 35, 35, 35, 35, 35, 35, 35, 15,110,110,110,110,
+ 35, 35, 35,672, 35, 35, 35, 35, 35, 35, 35, 15,110,110,110,110,
35, 35, 35, 35, 35,128, 35, 35, 35,110, 15, 15,120,120,120,120,
-668,668,668,668,668,668,668,668,668,668,668,668,668,668,668,668,
+673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
+
+/* block 115 */
+673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
+673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
+673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
+673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
+667,667,667,667,667,667,667,667,667,667,667,667,667,667,667,667,
+667,667,667,667,667,667,667,667,667,667,667,667,667,667,667,667,
+667,667,667,668,668,669,668,668,669,668,668,670,668,669,120,120,
+674,674,674,674,674,674,674,674,674,674,120,120,120,120,120,120,
/* block 116 */
-668,668,668,668,668,668,668,668,668,668,668,668,668,668,668,668,
-668,668,668,668,668,668,668,668,668,668,668,668,668,668,668,668,
-668,668,668,668,668,668,668,668,668,668,668,668,668,668,668,668,
-668,668,668,668,668,668,668,668,668,668,668,668,668,668,668,668,
-662,662,662,662,662,662,662,662,662,662,662,662,662,662,662,662,
-662,662,662,662,662,662,662,662,662,662,662,662,662,662,662,662,
-662,662,662,663,663,664,663,663,664,663,663,665,663,664,120,120,
-669,669,669,669,669,669,669,669,669,669,120,120,120,120,120,120,
+675,676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,
+676,676,676,676,676,676,676,676,676,676,676,676,675,676,676,676,
+676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,
+676,676,676,676,676,676,676,676,675,676,676,676,676,676,676,676,
+676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,
+676,676,676,676,675,676,676,676,676,676,676,676,676,676,676,676,
+676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,
+675,676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,
/* block 117 */
-670,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
-671,671,671,671,671,671,671,671,671,671,671,671,670,671,671,671,
-671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
-671,671,671,671,671,671,671,671,670,671,671,671,671,671,671,671,
-671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
-671,671,671,671,670,671,671,671,671,671,671,671,671,671,671,671,
-671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
-670,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+676,676,676,676,676,676,676,676,676,676,676,676,675,676,676,676,
+676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,
+676,676,676,676,676,676,676,676,675,676,676,676,676,676,676,676,
+676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,
+676,676,676,676,675,676,676,676,676,676,676,676,676,676,676,676,
+676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,
+675,676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,
+676,676,676,676,676,676,676,676,676,676,676,676,675,676,676,676,
/* block 118 */
-671,671,671,671,671,671,671,671,671,671,671,671,670,671,671,671,
-671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
-671,671,671,671,671,671,671,671,670,671,671,671,671,671,671,671,
-671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
-671,671,671,671,670,671,671,671,671,671,671,671,671,671,671,671,
-671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
-670,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
-671,671,671,671,671,671,671,671,671,671,671,671,670,671,671,671,
+676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,
+676,676,676,676,676,676,676,676,675,676,676,676,676,676,676,676,
+676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,
+676,676,676,676,675,676,676,676,676,676,676,676,676,676,676,676,
+676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,
+675,676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,
+676,676,676,676,676,676,676,676,676,676,676,676,675,676,676,676,
+676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,
/* block 119 */
-671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
-671,671,671,671,671,671,671,671,670,671,671,671,671,671,671,671,
-671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
-671,671,671,671,670,671,671,671,671,671,671,671,671,671,671,671,
-671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
-670,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
-671,671,671,671,671,671,671,671,671,671,671,671,670,671,671,671,
-671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+676,676,676,676,676,676,676,676,675,676,676,676,676,676,676,676,
+676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,
+676,676,676,676,675,676,676,676,676,676,676,676,676,676,676,676,
+676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,
+675,676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,
+676,676,676,676,676,676,676,676,676,676,676,676,675,676,676,676,
+676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,
+676,676,676,676,676,676,676,676,675,676,676,676,676,676,676,676,
/* block 120 */
-671,671,671,671,671,671,671,671,670,671,671,671,671,671,671,671,
-671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
-671,671,671,671,670,671,671,671,671,671,671,671,671,671,671,671,
-671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
-670,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
-671,671,671,671,671,671,671,671,671,671,671,671,670,671,671,671,
-671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
-671,671,671,671,671,671,671,671,670,671,671,671,671,671,671,671,
+676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,
+676,676,676,676,675,676,676,676,676,676,676,676,676,676,676,676,
+676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,
+675,676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,
+676,676,676,676,676,676,676,676,676,676,676,676,675,676,676,676,
+676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,
+676,676,676,676,676,676,676,676,675,676,676,676,676,676,676,676,
+676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,
/* block 121 */
-671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
-671,671,671,671,670,671,671,671,671,671,671,671,671,671,671,671,
-671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
-670,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
-671,671,671,671,671,671,671,671,671,671,671,671,670,671,671,671,
-671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
-671,671,671,671,671,671,671,671,670,671,671,671,671,671,671,671,
-671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+676,676,676,676,675,676,676,676,676,676,676,676,676,676,676,676,
+676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,
+675,676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,
+676,676,676,676,676,676,676,676,676,676,676,676,675,676,676,676,
+676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,
+676,676,676,676,676,676,676,676,675,676,676,676,676,676,676,676,
+676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,
+676,676,676,676,675,676,676,676,676,676,676,676,676,676,676,676,
/* block 122 */
-671,671,671,671,670,671,671,671,671,671,671,671,671,671,671,671,
-671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
-670,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
-671,671,671,671,671,671,671,671,671,671,671,671,670,671,671,671,
-671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
-671,671,671,671,671,671,671,671,670,671,671,671,671,671,671,671,
-671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
-671,671,671,671,670,671,671,671,671,671,671,671,671,671,671,671,
+676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,
+675,676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,
+676,676,676,676,676,676,676,676,676,676,676,676,675,676,676,676,
+676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,
+676,676,676,676,676,676,676,676,675,676,676,676,676,676,676,676,
+676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,
+676,676,676,676,675,676,676,676,676,676,676,676,676,676,676,676,
+676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,
/* block 123 */
-671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
-670,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
-671,671,671,671,671,671,671,671,671,671,671,671,670,671,671,671,
-671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
-671,671,671,671,671,671,671,671,670,671,671,671,671,671,671,671,
-671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
-671,671,671,671,670,671,671,671,671,671,671,671,671,671,671,671,
-671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+676,676,676,676,676,676,676,676,675,676,676,676,676,676,676,676,
+676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,676,
+676,676,676,676,120,120,120,120,120,120,120,120,120,120,120,120,
+359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
+359,359,359,359,359,359,359,120,120,120,120,360,360,360,360,360,
+360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,
+360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,
+360,360,360,360,360,360,360,360,360,360,360,360,120,120,120,120,
/* block 124 */
-671,671,671,671,671,671,671,671,670,671,671,671,671,671,671,671,
-671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
-671,671,671,671,120,120,120,120,120,120,120,120,120,120,120,120,
-357,357,357,357,357,357,357,357,357,357,357,357,357,357,357,357,
-357,357,357,357,357,357,357,120,120,120,120,358,358,358,358,358,
-358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,
-358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,
-358,358,358,358,358,358,358,358,358,358,358,358,120,120,120,120,
+677,677,677,677,677,677,677,677,677,677,677,677,677,677,677,677,
+677,677,677,677,677,677,677,677,677,677,677,677,677,677,677,677,
+677,677,677,677,677,677,677,677,677,677,677,677,677,677,677,677,
+677,677,677,677,677,677,677,677,677,677,677,677,677,677,677,677,
+677,677,677,677,677,677,677,677,677,677,677,677,677,677,677,677,
+677,677,677,677,677,677,677,677,677,677,677,677,677,677,677,677,
+677,677,677,677,677,677,677,677,677,677,677,677,677,677,677,677,
+677,677,677,677,677,677,677,677,677,677,677,677,677,677,677,677,
/* block 125 */
-672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,
-672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,
-672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,
-672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,
-672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,
-672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,
-672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,
-672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,
+678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,
+678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,
+678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,
+678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,
+678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,
+678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,
+678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,
+678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,
/* block 126 */
-673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
-673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
-673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
-673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
-673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
-673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
-673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
-673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
+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,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,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,120,120,
+591,591,591,591,591,591,591,591,591,591,591,591,591,591,591,591,
/* block 127 */
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,120,120,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-
-/* block 128 */
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,120,120,120,120,120,120,
+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,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,591,591,591,591,
+591,591,591,591,591,591,591,591,591,591,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-/* block 129 */
+/* block 128 */
35, 35, 35, 35, 35, 35, 35,120,120,120,120,120,120,120,120,120,
120,120,120,206,206,206,206,206,120,120,120,120,120,214,211,214,
-214,214,214,214,214,214,214,214,214,674,214,214,214,214,214,214,
+214,214,214,214,214,214,214,214,214,679,214,214,214,214,214,214,
214,214,214,214,214,214,214,120,214,214,214,214,214,120,214,120,
214,214,120,214,214,120,214,214,214,214,214,214,214,214,214,214,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+
+/* block 129 */
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,252,252,252,252,252,252,252,252,252,252,252,252,252,252,
+252,252,252,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
/* block 130 */
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,675,675,675,675,675,675,675,675,675,675,675,675,675,675,
-675,675,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-120,120,120,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
/* block 131 */
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,680,681,
+221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
/* block 132 */
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224, 8, 7,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+120,120,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,120,120,120,120,120,120,120,221,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-
-/* block 133 */
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-120,120,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-224,224,676,224,224,224,224,224,224,224,224,224,219,677,120,120,
+225,225,682,225,225,225,225,225,225,225,225,225,219,683,221,221,
-/* block 134 */
+/* block 133 */
113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
5, 5, 5, 5, 5, 5, 5, 7, 8, 5,120,120,120,120,120,120,
-113,113,113,113,113,113,113,113,113,113,113,113,113,113,552,552,
+113,113,113,113,113,113,113,113,113,113,113,113,113,113,557,557,
5, 10, 10, 16, 16, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7,
- 8, 7, 8, 7, 8,556,556, 7, 8, 5, 5, 5, 5, 16, 16, 16,
+ 8, 7, 8, 7, 8,561,561, 7, 8, 5, 5, 5, 5, 16, 16, 16,
5, 5, 5,120, 5, 5, 5, 5, 10, 7, 8, 7, 8, 7, 8, 5,
5, 5, 9, 10, 9, 9, 9,120, 5, 6, 5, 5,120,120,120,120,
-224,224,224,224,224,120,224,224,224,224,224,224,224,224,224,224,
+225,225,225,225,225,120,225,225,225,225,225,225,225,225,225,225,
-/* block 135 */
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,120,120, 24,
+/* block 134 */
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,120,120, 24,
-/* block 136 */
+/* block 135 */
120, 5, 5, 5, 6, 5, 5, 5, 7, 8, 5, 9, 5, 10, 5, 5,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 5, 5, 9, 9, 9, 5,
5, 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, 7, 5, 8, 15, 16,
15, 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, 7, 9, 8, 9, 7,
- 8,555,560,561,555,555,578,578,578,578,578,578,578,578,578,578,
-569,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
+ 8,560,565,566,560,560,583,583,583,583,583,583,583,583,583,583,
+574,583,583,583,583,583,583,583,583,583,583,583,583,583,583,583,
-/* block 137 */
-578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
-578,578,578,578,578,578,578,578,578,578,578,578,578,578,678,678,
-581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,
-581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,120,
-120,120,581,581,581,581,581,581,120,120,581,581,581,581,581,581,
-120,120,581,581,581,581,581,581,120,120,581,581,581,120,120,120,
+/* block 136 */
+583,583,583,583,583,583,583,583,583,583,583,583,583,583,583,583,
+583,583,583,583,583,583,583,583,583,583,583,583,583,583,684,684,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,120,
+120,120,586,586,586,586,586,586,120,120,586,586,586,586,586,586,
+120,120,586,586,586,586,586,586,120,120,586,586,586,120,120,120,
6, 6, 9, 15, 20, 6, 6,120, 20, 9, 9, 9, 9, 20, 20,120,
-511,511,511,511,511,511,511,511,511, 24, 24, 24, 20, 20,120,120,
+516,516,516,516,516,516,516,516,516, 24, 24, 24, 20, 20,120,120,
-/* block 138 */
-679,679,679,679,679,679,679,679,679,679,679,679,120,679,679,679,
-679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,
-679,679,679,679,679,679,679,120,679,679,679,679,679,679,679,679,
-679,679,679,679,679,679,679,679,679,679,679,120,679,679,120,679,
-679,679,679,679,679,679,679,679,679,679,679,679,679,679,120,120,
-679,679,679,679,679,679,679,679,679,679,679,679,679,679,120,120,
+/* block 137 */
+685,685,685,685,685,685,685,685,685,685,685,685,120,685,685,685,
+685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,
+685,685,685,685,685,685,685,120,685,685,685,685,685,685,685,685,
+685,685,685,685,685,685,685,685,685,685,685,120,685,685,120,685,
+685,685,685,685,685,685,685,685,685,685,685,685,685,685,120,120,
+685,685,685,685,685,685,685,685,685,685,685,685,685,685,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+/* block 138 */
+685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,
+685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,
+685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,
+685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,
+685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,
+685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,
+685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,
+685,685,685,685,685,685,685,685,685,685,685,120,120,120,120,120,
+
/* block 139 */
-679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,
-679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,
-679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,
-679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,
-679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,
-679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,
-679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,
-679,679,679,679,679,679,679,679,679,679,679,120,120,120,120,120,
+686,686,687,120,120,120,120,688,688,688,688,688,688,688,688,688,
+688,688,688,688,688,688,688,688,688,688,688,688,688,688,688,688,
+688,688,688,688,688,688,688,688,688,688,688,688,688,688,688,688,
+688,688,688,688,120,120,120,689,689,689,689,689,689,689,689,689,
+690,690,690,690,690,690,690,690,690,690,690,690,690,690,690,690,
+690,690,690,690,690,690,690,690,690,690,690,690,690,690,690,690,
+690,690,690,690,690,690,690,690,690,690,690,690,690,690,690,690,
+690,690,690,690,690,691,691,691,691,692,692,692,692,692,692,692,
/* block 140 */
-680,680,680,120,120,120,120,681,681,681,681,681,681,681,681,681,
-681,681,681,681,681,681,681,681,681,681,681,681,681,681,681,681,
-681,681,681,681,681,681,681,681,681,681,681,681,681,681,681,681,
-681,681,681,681,120,120,120,682,682,682,682,682,682,682,682,682,
-683,683,683,683,683,683,683,683,683,683,683,683,683,683,683,683,
-683,683,683,683,683,683,683,683,683,683,683,683,683,683,683,683,
-683,683,683,683,683,683,683,683,683,683,683,683,683,683,683,683,
-683,683,683,683,683,684,684,684,684,685,685,685,685,685,685,685,
-
-/* block 141 */
-685,685,685,685,685,685,685,685,685,685,684,684,685,685,685,120,
+692,692,692,692,692,692,692,692,692,692,691,691,692,692,692,120,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,120,120,120,
-685,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+692,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,113,120,120,
-/* block 142 */
+/* block 141 */
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
@@ -3148,499 +3164,519 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-/* block 143 */
-686,686,686,686,686,686,686,686,686,686,686,686,686,686,686,686,
-686,686,686,686,686,686,686,686,686,686,686,686,686,120,120,120,
-687,687,687,687,687,687,687,687,687,687,687,687,687,687,687,687,
-687,687,687,687,687,687,687,687,687,687,687,687,687,687,687,687,
-687,687,687,687,687,687,687,687,687,687,687,687,687,687,687,687,
-687,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-688,689,689,689,689,689,689,689,689,689,689,689,689,689,689,689,
-689,689,689,689,689,689,689,689,689,689,689,689,120,120,120,120,
-
-/* block 144 */
-690,690,690,690,690,690,690,690,690,690,690,690,690,690,690,690,
-690,690,690,690,690,690,690,690,690,690,690,690,690,690,690,690,
-691,691,691,691,120,120,120,120,120,120,120,120,120,690,690,690,
-692,692,692,692,692,692,692,692,692,692,692,692,692,692,692,692,
-692,693,692,692,692,692,692,692,692,692,693,120,120,120,120,120,
+/* block 142 */
+693,693,693,693,693,693,693,693,693,693,693,693,693,693,693,693,
+693,693,693,693,693,693,693,693,693,693,693,693,693,120,120,120,
694,694,694,694,694,694,694,694,694,694,694,694,694,694,694,694,
694,694,694,694,694,694,694,694,694,694,694,694,694,694,694,694,
-694,694,694,694,694,694,695,695,695,695,695,120,120,120,120,120,
-
-/* block 145 */
-696,696,696,696,696,696,696,696,696,696,696,696,696,696,696,696,
-696,696,696,696,696,696,696,696,696,696,696,696,696,696,120,697,
-698,698,698,698,698,698,698,698,698,698,698,698,698,698,698,698,
-698,698,698,698,698,698,698,698,698,698,698,698,698,698,698,698,
-698,698,698,698,120,120,120,120,698,698,698,698,698,698,698,698,
-699,700,700,700,700,700,120,120,120,120,120,120,120,120,120,120,
-120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+694,694,694,694,694,694,694,694,694,694,694,694,694,694,694,694,
+694,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+695,696,696,696,696,696,696,696,696,696,696,696,696,696,696,696,
+696,696,696,696,696,696,696,696,696,696,696,696,120,120,120,120,
-/* block 146 */
+/* block 143 */
+697,697,697,697,697,697,697,697,697,697,697,697,697,697,697,697,
+697,697,697,697,697,697,697,697,697,697,697,697,697,697,697,697,
+698,698,698,698,120,120,120,120,120,120,120,120,120,697,697,697,
+699,699,699,699,699,699,699,699,699,699,699,699,699,699,699,699,
+699,700,699,699,699,699,699,699,699,699,700,120,120,120,120,120,
701,701,701,701,701,701,701,701,701,701,701,701,701,701,701,701,
701,701,701,701,701,701,701,701,701,701,701,701,701,701,701,701,
-701,701,701,701,701,701,701,701,702,702,702,702,702,702,702,702,
-702,702,702,702,702,702,702,702,702,702,702,702,702,702,702,702,
-702,702,702,702,702,702,702,702,702,702,702,702,702,702,702,702,
-703,703,703,703,703,703,703,703,703,703,703,703,703,703,703,703,
-703,703,703,703,703,703,703,703,703,703,703,703,703,703,703,703,
-703,703,703,703,703,703,703,703,703,703,703,703,703,703,703,703,
+701,701,701,701,701,701,702,702,702,702,702,120,120,120,120,120,
-/* block 147 */
-704,704,704,704,704,704,704,704,704,704,704,704,704,704,704,704,
-704,704,704,704,704,704,704,704,704,704,704,704,704,704,120,120,
-705,705,705,705,705,705,705,705,705,705,120,120,120,120,120,120,
-706,706,706,706,706,706,706,706,706,706,706,706,706,706,706,706,
-706,706,706,706,706,706,706,706,706,706,706,706,706,706,706,706,
-706,706,706,706,120,120,120,120,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,120,120,120,120,
+/* block 144 */
+703,703,703,703,703,703,703,703,703,703,703,703,703,703,703,703,
+703,703,703,703,703,703,703,703,703,703,703,703,703,703,120,704,
+705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,
+705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,
+705,705,705,705,120,120,120,120,705,705,705,705,705,705,705,705,
+706,707,707,707,707,707,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-/* block 148 */
+/* block 145 */
708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,
708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,
-708,708,708,708,708,708,708,708,120,120,120,120,120,120,120,120,
+708,708,708,708,708,708,708,708,709,709,709,709,709,709,709,709,
709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,
709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,
-709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,
-709,709,709,709,120,120,120,120,120,120,120,120,120,120,120,710,
+710,710,710,710,710,710,710,710,710,710,710,710,710,710,710,710,
+710,710,710,710,710,710,710,710,710,710,710,710,710,710,710,710,
+710,710,710,710,710,710,710,710,710,710,710,710,710,710,710,710,
+
+/* block 146 */
+711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
+711,711,711,711,711,711,711,711,711,711,711,711,711,711,120,120,
+712,712,712,712,712,712,712,712,712,712,120,120,120,120,120,120,
+713,713,713,713,713,713,713,713,713,713,713,713,713,713,713,713,
+713,713,713,713,713,713,713,713,713,713,713,713,713,713,713,713,
+713,713,713,713,120,120,120,120,714,714,714,714,714,714,714,714,
+714,714,714,714,714,714,714,714,714,714,714,714,714,714,714,714,
+714,714,714,714,714,714,714,714,714,714,714,714,120,120,120,120,
+
+/* block 147 */
+715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,
+715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,
+715,715,715,715,715,715,715,715,120,120,120,120,120,120,120,120,
+716,716,716,716,716,716,716,716,716,716,716,716,716,716,716,716,
+716,716,716,716,716,716,716,716,716,716,716,716,716,716,716,716,
+716,716,716,716,716,716,716,716,716,716,716,716,716,716,716,716,
+716,716,716,716,120,120,120,120,120,120,120,120,120,120,120,717,
+718,718,718,718,718,718,718,718,718,718,718,120,718,718,718,718,
+
+/* block 148 */
+718,718,718,718,718,718,718,718,718,718,718,120,718,718,718,718,
+718,718,718,120,718,718,120,719,719,719,719,719,719,719,719,719,
+719,719,120,719,719,719,719,719,719,719,719,719,719,719,719,719,
+719,719,120,719,719,719,719,719,719,719,120,719,719,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
/* block 149 */
-711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
-711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
-711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
-711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
-711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
-711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
-711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
-711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
+720,720,720,720,720,720,720,720,720,720,720,720,720,720,720,720,
+720,720,720,720,720,720,720,720,720,720,720,720,720,720,720,720,
+720,720,720,720,720,720,720,720,720,720,720,720,720,720,720,720,
+720,720,720,720,720,720,720,720,720,720,720,720,720,720,720,720,
+720,720,720,720,720,720,720,720,720,720,720,720,720,720,720,720,
+720,720,720,720,720,720,720,720,720,720,720,720,720,720,720,720,
+720,720,720,720,720,720,720,720,720,720,720,720,720,720,720,720,
+720,720,720,720,720,720,720,720,720,720,720,720,720,720,720,720,
/* block 150 */
-711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
-711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
-711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
-711,711,711,711,711,711,711,120,120,120,120,120,120,120,120,120,
-711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
-711,711,711,711,711,711,120,120,120,120,120,120,120,120,120,120,
-711,711,711,711,711,711,711,711,120,120,120,120,120,120,120,120,
+720,720,720,720,720,720,720,720,720,720,720,720,720,720,720,720,
+720,720,720,720,720,720,720,720,720,720,720,720,720,720,720,720,
+720,720,720,720,720,720,720,720,720,720,720,720,720,720,720,720,
+720,720,720,720,720,720,720,120,120,120,120,120,120,120,120,120,
+720,720,720,720,720,720,720,720,720,720,720,720,720,720,720,720,
+720,720,720,720,720,720,120,120,120,120,120,120,120,120,120,120,
+720,720,720,720,720,720,720,720,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
/* block 151 */
-712,712,712,712,712,712,120,120,712,120,712,712,712,712,712,712,
-712,712,712,712,712,712,712,712,712,712,712,712,712,712,712,712,
-712,712,712,712,712,712,712,712,712,712,712,712,712,712,712,712,
-712,712,712,712,712,712,120,712,712,120,120,120,712,120,120,712,
-713,713,713,713,713,713,713,713,713,713,713,713,713,713,713,713,
-713,713,713,713,713,713,120,714,715,715,715,715,715,715,715,715,
-716,716,716,716,716,716,716,716,716,716,716,716,716,716,716,716,
-716,716,716,716,716,716,716,717,717,718,718,718,718,718,718,718,
-
-/* block 152 */
-719,719,719,719,719,719,719,719,719,719,719,719,719,719,719,719,
-719,719,719,719,719,719,719,719,719,719,719,719,719,719,719,120,
-120,120,120,120,120,120,120,720,720,720,720,720,720,720,720,720,
+110,110,110,110,110,110,120,110,110,110,110,110,110,110,110,110,
+110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
+110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
+110,120,110,110,110,110,110,110,110,110,110,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 152 */
+721,721,721,721,721,721,120,120,721,120,721,721,721,721,721,721,
+721,721,721,721,721,721,721,721,721,721,721,721,721,721,721,721,
721,721,721,721,721,721,721,721,721,721,721,721,721,721,721,721,
-721,721,721,120,721,721,120,120,120,120,120,722,722,722,722,722,
+721,721,721,721,721,721,120,721,721,120,120,120,721,120,120,721,
+722,722,722,722,722,722,722,722,722,722,722,722,722,722,722,722,
+722,722,722,722,722,722,120,723,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,726,726,727,727,727,727,727,727,727,
/* block 153 */
-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,120,120,120,725,
-726,726,726,726,726,726,726,726,726,726,726,726,726,726,726,726,
-726,726,726,726,726,726,726,726,726,726,120,120,120,120,120,727,
-120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+728,728,728,728,728,728,728,728,728,728,728,728,728,728,728,728,
+728,728,728,728,728,728,728,728,728,728,728,728,728,728,728,120,
+120,120,120,120,120,120,120,729,729,729,729,729,729,729,729,729,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+730,730,730,730,730,730,730,730,730,730,730,730,730,730,730,730,
+730,730,730,120,730,730,120,120,120,120,120,731,731,731,731,731,
/* block 154 */
-728,728,728,728,728,728,728,728,728,728,728,728,728,728,728,728,
-728,728,728,728,728,728,728,728,728,728,728,728,728,728,728,728,
-729,729,729,729,729,729,729,729,729,729,729,729,729,729,729,729,
-729,729,729,729,729,729,729,729,120,120,120,120,730,730,729,729,
-730,730,730,730,730,730,730,730,730,730,730,730,730,730,730,730,
-120,120,730,730,730,730,730,730,730,730,730,730,730,730,730,730,
-730,730,730,730,730,730,730,730,730,730,730,730,730,730,730,730,
-730,730,730,730,730,730,730,730,730,730,730,730,730,730,730,730,
+732,732,732,732,732,732,732,732,732,732,732,732,732,732,732,732,
+732,732,732,732,732,732,733,733,733,733,733,733,120,120,120,734,
+735,735,735,735,735,735,735,735,735,735,735,735,735,735,735,735,
+735,735,735,735,735,735,735,735,735,735,120,120,120,120,120,736,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
/* block 155 */
-731,732,732,732,120,732,732,120,120,120,120,120,732,732,732,732,
-731,731,731,731,120,731,731,731,120,731,731,731,731,731,731,731,
-731,731,731,731,731,731,731,731,731,731,731,731,731,731,731,731,
-731,731,731,731,731,731,120,120,732,732,732,120,120,120,120,732,
-733,733,733,733,733,733,733,733,733,120,120,120,120,120,120,120,
-734,734,734,734,734,734,734,734,734,120,120,120,120,120,120,120,
-735,735,735,735,735,735,735,735,735,735,735,735,735,735,735,735,
-735,735,735,735,735,735,735,735,735,735,735,735,735,736,736,737,
+737,737,737,737,737,737,737,737,737,737,737,737,737,737,737,737,
+737,737,737,737,737,737,737,737,737,737,737,737,737,737,737,737,
+738,738,738,738,738,738,738,738,738,738,738,738,738,738,738,738,
+738,738,738,738,738,738,738,738,120,120,120,120,739,739,738,738,
+739,739,739,739,739,739,739,739,739,739,739,739,739,739,739,739,
+120,120,739,739,739,739,739,739,739,739,739,739,739,739,739,739,
+739,739,739,739,739,739,739,739,739,739,739,739,739,739,739,739,
+739,739,739,739,739,739,739,739,739,739,739,739,739,739,739,739,
/* block 156 */
-738,738,738,738,738,738,738,738,738,738,738,738,738,738,738,738,
-738,738,738,738,738,738,738,738,738,738,738,738,738,739,739,739,
-120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-740,740,740,740,740,740,740,740,741,740,740,740,740,740,740,740,
+740,741,741,741,120,741,741,120,120,120,120,120,741,741,741,741,
+740,740,740,740,120,740,740,740,120,740,740,740,740,740,740,740,
740,740,740,740,740,740,740,740,740,740,740,740,740,740,740,740,
-740,740,740,740,740,742,742,120,120,120,120,743,743,743,743,743,
-744,744,744,744,744,744,744,120,120,120,120,120,120,120,120,120,
+740,740,740,740,740,740,120,120,741,741,741,120,120,120,120,741,
+742,742,742,742,742,742,742,742,742,120,120,120,120,120,120,120,
+743,743,743,743,743,743,743,743,743,120,120,120,120,120,120,120,
+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,745,745,746,
/* block 157 */
-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,745,745,745,745,745,745,745,745,
-745,745,745,745,745,745,120,120,120,746,746,746,746,746,746,746,
747,747,747,747,747,747,747,747,747,747,747,747,747,747,747,747,
-747,747,747,747,747,747,120,120,748,748,748,748,748,748,748,748,
+747,747,747,747,747,747,747,747,747,747,747,747,747,748,748,748,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+749,749,749,749,749,749,749,749,750,749,749,749,749,749,749,749,
749,749,749,749,749,749,749,749,749,749,749,749,749,749,749,749,
-749,749,749,120,120,120,120,120,750,750,750,750,750,750,750,750,
+749,749,749,749,749,751,751,120,120,120,120,752,752,752,752,752,
+753,753,754,753,753,753,753,120,120,120,120,120,120,120,120,120,
/* block 158 */
-751,751,751,751,751,751,751,751,751,751,751,751,751,751,751,751,
-751,751,120,120,120,120,120,120,120,752,752,752,752,120,120,120,
-120,120,120,120,120,120,120,120,120,753,753,753,753,753,753,753,
+755,755,755,755,755,755,755,755,755,755,755,755,755,755,755,755,
+755,755,755,755,755,755,755,755,755,755,755,755,755,755,755,755,
+755,755,755,755,755,755,755,755,755,755,755,755,755,755,755,755,
+755,755,755,755,755,755,120,120,120,756,756,756,756,756,756,756,
+757,757,757,757,757,757,757,757,757,757,757,757,757,757,757,757,
+757,757,757,757,757,757,120,120,758,758,758,758,758,758,758,758,
+759,759,759,759,759,759,759,759,759,759,759,759,759,759,759,759,
+759,759,759,120,120,120,120,120,760,760,760,760,760,760,760,760,
+
+/* block 159 */
+761,761,761,761,761,761,761,761,761,761,761,761,761,761,761,761,
+761,761,120,120,120,120,120,120,120,762,762,762,762,120,120,120,
+120,120,120,120,120,120,120,120,120,763,763,763,763,763,763,763,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-/* block 159 */
-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,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,754,754,754,754,754,120,120,120,120,120,120,120,
+/* block 160 */
+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,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-/* block 160 */
-755,755,755,755,755,755,755,755,755,755,755,755,755,755,755,755,
-755,755,755,755,755,755,755,755,755,755,755,755,755,755,755,755,
-755,755,755,755,755,755,755,755,755,755,755,755,755,755,755,755,
-755,755,755,120,120,120,120,120,120,120,120,120,120,120,120,120,
-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,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,120,120,120,120,120,120,120,757,757,757,757,757,757,
-
/* block 161 */
-758,758,758,758,758,758,758,758,758,758,758,758,758,758,758,758,
-758,758,758,758,758,758,758,758,758,758,758,758,758,758,758,758,
-758,758,758,758,759,759,759,759,120,120,120,120,120,120,120,120,
-760,760,760,760,760,760,760,760,760,760,120,120,120,120,120,120,
-120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+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,
+765,765,765,120,120,120,120,120,120,120,120,120,120,120,120,120,
+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,
+766,766,766,120,120,120,120,120,120,120,767,767,767,767,767,767,
/* block 162 */
+768,768,768,768,768,768,768,768,768,768,768,768,768,768,768,768,
+768,768,768,768,768,768,768,768,768,768,768,768,768,768,768,768,
+768,768,768,768,769,769,769,769,120,120,120,120,120,120,120,120,
+770,770,770,770,770,770,770,770,770,770,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-761,761,761,761,761,761,761,761,761,761,761,761,761,761,761,761,
-761,761,761,761,761,761,761,761,761,761,761,761,761,761,761,120,
/* block 163 */
-762,762,762,762,762,762,762,762,762,762,762,762,762,762,762,762,
-762,762,762,762,762,762,762,762,762,762,762,762,762,762,762,762,
-762,762,762,762,762,762,762,762,762,762,120,763,763,764,120,120,
-762,762,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+771,771,771,771,771,771,771,771,771,771,771,771,771,771,771,771,
+771,771,771,771,771,771,771,771,771,771,771,771,771,771,771,120,
/* block 164 */
-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,765,120,120,120,120,120,120,120,120,
-767,767,767,767,767,767,767,767,767,767,767,767,767,767,767,767,
-767,767,767,767,767,767,768,768,768,768,768,768,768,768,768,768,
-768,769,769,769,769,770,770,770,770,770,120,120,120,120,120,120,
+772,772,772,772,772,772,772,772,772,772,772,772,772,772,772,772,
+772,772,772,772,772,772,772,772,772,772,772,772,772,772,772,772,
+772,772,772,772,772,772,772,772,772,772,120,773,773,774,120,120,
+772,772,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
/* block 165 */
+775,775,775,775,775,775,775,775,775,775,775,775,775,775,775,775,
+775,775,775,775,775,775,775,775,775,775,775,775,775,776,776,776,
+776,776,776,776,776,776,776,775,120,120,120,120,120,120,120,120,
+777,777,777,777,777,777,777,777,777,777,777,777,777,777,777,777,
+777,777,777,777,777,777,778,778,778,778,778,778,778,778,778,778,
+778,779,779,779,779,780,780,780,780,780,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+781,781,781,781,781,781,781,781,781,781,781,781,781,781,781,781,
+
+/* block 166 */
+781,781,782,782,782,782,783,783,783,783,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-771,771,771,771,771,771,771,771,771,771,771,771,771,771,771,771,
-771,771,771,771,771,772,772,772,772,772,772,772,120,120,120,120,
+784,784,784,784,784,784,784,784,784,784,784,784,784,784,784,784,
+784,784,784,784,784,785,785,785,785,785,785,785,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-773,773,773,773,773,773,773,773,773,773,773,773,773,773,773,773,
-773,773,773,773,773,773,773,120,120,120,120,120,120,120,120,120,
-
-/* block 166 */
-774,775,774,776,776,776,776,776,776,776,776,776,776,776,776,776,
-776,776,776,776,776,776,776,776,776,776,776,776,776,776,776,776,
-776,776,776,776,776,776,776,776,776,776,776,776,776,776,776,776,
-776,776,776,776,776,776,776,776,775,775,775,775,775,775,775,775,
-775,775,775,775,775,775,775,777,777,777,777,777,777,777,120,120,
-120,120,778,778,778,778,778,778,778,778,778,778,778,778,778,778,
-778,778,778,778,778,778,779,779,779,779,779,779,779,779,779,779,
-120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,775,
+786,786,786,786,786,786,786,786,786,786,786,786,786,786,786,786,
+786,786,786,786,786,786,786,120,120,120,120,120,120,120,120,120,
/* block 167 */
-780,780,781,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,782,782,782,782,782,782,782,
-781,781,781,780,780,780,780,781,781,780,780,783,783,784,783,783,
-783,783,120,120,120,120,120,120,120,120,120,120,120,784,120,120,
-785,785,785,785,785,785,785,785,785,785,785,785,785,785,785,785,
-785,785,785,785,785,785,785,785,785,120,120,120,120,120,120,120,
-786,786,786,786,786,786,786,786,786,786,120,120,120,120,120,120,
+787,788,787,789,789,789,789,789,789,789,789,789,789,789,789,789,
+789,789,789,789,789,789,789,789,789,789,789,789,789,789,789,789,
+789,789,789,789,789,789,789,789,789,789,789,789,789,789,789,789,
+789,789,789,789,789,789,789,789,788,788,788,788,788,788,788,788,
+788,788,788,788,788,788,788,790,790,790,790,790,790,790,120,120,
+120,120,791,791,791,791,791,791,791,791,791,791,791,791,791,791,
+791,791,791,791,791,791,792,792,792,792,792,792,792,792,792,792,
+788,789,789,788,788,789,120,120,120,120,120,120,120,120,120,788,
/* block 168 */
-787,787,787,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,788,788,788,788,787,787,787,787,787,789,787,787,787,
-787,787,787,787,787,120,790,790,790,790,790,790,790,790,790,790,
-791,791,791,791,788,789,789,788,120,120,120,120,120,120,120,120,
-792,792,792,792,792,792,792,792,792,792,792,792,792,792,792,792,
-792,792,792,792,792,792,792,792,792,792,792,792,792,792,792,792,
-792,792,792,793,794,794,792,120,120,120,120,120,120,120,120,120,
+793,793,794,795,795,795,795,795,795,795,795,795,795,795,795,795,
+795,795,795,795,795,795,795,795,795,795,795,795,795,795,795,795,
+795,795,795,795,795,795,795,795,795,795,795,795,795,795,795,795,
+794,794,794,793,793,793,793,794,794,793,793,796,796,797,796,796,
+796,796,793,120,120,120,120,120,120,120,120,120,120,797,120,120,
+798,798,798,798,798,798,798,798,798,798,798,798,798,798,798,798,
+798,798,798,798,798,798,798,798,798,120,120,120,120,120,120,120,
+799,799,799,799,799,799,799,799,799,799,120,120,120,120,120,120,
/* block 169 */
-795,795,796,797,797,797,797,797,797,797,797,797,797,797,797,797,
-797,797,797,797,797,797,797,797,797,797,797,797,797,797,797,797,
-797,797,797,797,797,797,797,797,797,797,797,797,797,797,797,797,
-797,797,797,796,796,796,795,795,795,795,795,795,795,795,795,796,
-796,797,798,798,797,799,799,799,799,795,795,795,795,799,796,795,
-800,800,800,800,800,800,800,800,800,800,797,799,797,799,799,799,
-120,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,
-801,801,801,801,801,120,120,120,120,120,120,120,120,120,120,120,
+800,800,800,801,801,801,801,801,801,801,801,801,801,801,801,801,
+801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,
+801,801,801,801,801,801,801,800,800,800,800,800,802,800,800,800,
+800,800,800,800,800,120,803,803,803,803,803,803,803,803,803,803,
+804,804,804,804,801,802,802,801,120,120,120,120,120,120,120,120,
+805,805,805,805,805,805,805,805,805,805,805,805,805,805,805,805,
+805,805,805,805,805,805,805,805,805,805,805,805,805,805,805,805,
+805,805,805,806,807,807,805,120,120,120,120,120,120,120,120,120,
/* block 170 */
-802,802,802,802,802,802,802,802,802,802,802,802,802,802,802,802,
-802,802,120,802,802,802,802,802,802,802,802,802,802,802,802,802,
-802,802,802,802,802,802,802,802,802,802,802,802,803,803,803,804,
-804,804,803,803,804,803,804,804,805,805,805,805,805,805,804,120,
+808,808,809,810,810,810,810,810,810,810,810,810,810,810,810,810,
+810,810,810,810,810,810,810,810,810,810,810,810,810,810,810,810,
+810,810,810,810,810,810,810,810,810,810,810,810,810,810,810,810,
+810,810,810,809,809,809,808,808,808,808,808,808,808,808,808,809,
+809,810,811,811,810,812,812,812,812,808,808,808,808,812,809,808,
+813,813,813,813,813,813,813,813,813,813,810,812,810,812,812,812,
+120,814,814,814,814,814,814,814,814,814,814,814,814,814,814,814,
+814,814,814,814,814,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 171 */
+815,815,815,815,815,815,815,815,815,815,815,815,815,815,815,815,
+815,815,120,815,815,815,815,815,815,815,815,815,815,815,815,815,
+815,815,815,815,815,815,815,815,815,815,815,815,816,816,816,817,
+817,817,816,816,817,816,817,817,818,818,818,818,818,818,817,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-/* block 171 */
-806,806,806,806,806,806,806,120,806,120,806,806,806,806,120,806,
-806,806,806,806,806,806,806,806,806,806,806,806,806,806,120,806,
-806,806,806,806,806,806,806,806,806,807,120,120,120,120,120,120,
-808,808,808,808,808,808,808,808,808,808,808,808,808,808,808,808,
-808,808,808,808,808,808,808,808,808,808,808,808,808,808,808,808,
-808,808,808,808,808,808,808,808,808,808,808,808,808,808,808,809,
-810,810,810,809,809,809,809,809,809,809,809,120,120,120,120,120,
-811,811,811,811,811,811,811,811,811,811,120,120,120,120,120,120,
-
/* block 172 */
-812,813,814,815,120,816,816,816,816,816,816,816,816,120,120,816,
-816,120,120,816,816,816,816,816,816,816,816,816,816,816,816,816,
-816,816,816,816,816,816,816,816,816,120,816,816,816,816,816,816,
-816,120,816,816,120,816,816,816,816,816,120,817,813,816,818,814,
-812,814,814,814,814,120,120,814,814,120,120,814,814,814,120,120,
-816,120,120,120,120,120,120,818,120,120,120,120,120,816,816,816,
-816,816,814,814,120,120,812,812,812,812,812,812,812,120,120,120,
-812,812,812,812,812,120,120,120,120,120,120,120,120,120,120,120,
+819,819,819,819,819,819,819,120,819,120,819,819,819,819,120,819,
+819,819,819,819,819,819,819,819,819,819,819,819,819,819,120,819,
+819,819,819,819,819,819,819,819,819,820,120,120,120,120,120,120,
+821,821,821,821,821,821,821,821,821,821,821,821,821,821,821,821,
+821,821,821,821,821,821,821,821,821,821,821,821,821,821,821,821,
+821,821,821,821,821,821,821,821,821,821,821,821,821,821,821,822,
+823,823,823,822,822,822,822,822,822,822,822,120,120,120,120,120,
+824,824,824,824,824,824,824,824,824,824,120,120,120,120,120,120,
/* block 173 */
-819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,
-819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,
-819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,
-819,819,819,819,819,820,820,820,821,821,821,821,821,821,821,821,
-820,820,821,821,821,820,821,819,819,819,819,822,822,822,822,822,
-823,823,823,823,823,823,823,823,823,823,822,822,120,822,821,819,
-819,819,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+825,826,827,828,120,829,829,829,829,829,829,829,829,120,120,829,
+829,120,120,829,829,829,829,829,829,829,829,829,829,829,829,829,
+829,829,829,829,829,829,829,829,829,120,829,829,829,829,829,829,
+829,120,829,829,120,829,829,829,829,829,120,830,826,829,831,827,
+825,827,827,827,827,120,120,827,827,120,120,827,827,827,120,120,
+829,120,120,120,120,120,120,831,120,120,120,120,120,829,829,829,
+829,829,827,827,120,120,825,825,825,825,825,825,825,120,120,120,
+825,825,825,825,825,120,120,120,120,120,120,120,120,120,120,120,
/* block 174 */
-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,826,827,827,827,827,827,827,826,827,826,826,825,826,827,
-827,826,827,827,824,824,828,824,120,120,120,120,120,120,120,120,
-829,829,829,829,829,829,829,829,829,829,120,120,120,120,120,120,
-120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+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,832,
+832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,
+832,832,832,832,832,833,833,833,834,834,834,834,834,834,834,834,
+833,833,834,834,834,833,834,832,832,832,832,835,835,835,835,835,
+836,836,836,836,836,836,836,836,836,836,835,835,120,835,834,832,
+832,832,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
/* block 175 */
-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,
-832,832,833,833,833,833,120,120,832,832,832,832,833,833,832,833,
-833,834,834,834,834,834,834,834,834,834,834,834,834,834,834,834,
-834,834,834,834,834,834,834,834,830,830,830,830,833,833,120,120,
+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,
+838,839,839,840,840,840,840,840,840,839,840,839,839,838,839,840,
+840,839,840,840,837,837,841,837,120,120,120,120,120,120,120,120,
+842,842,842,842,842,842,842,842,842,842,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
/* block 176 */
-835,835,835,835,835,835,835,835,835,835,835,835,835,835,835,835,
-835,835,835,835,835,835,835,835,835,835,835,835,835,835,835,835,
-835,835,835,835,835,835,835,835,835,835,835,835,835,835,835,835,
-836,836,836,837,837,837,837,837,837,837,837,836,836,837,836,837,
-837,838,838,838,835,120,120,120,120,120,120,120,120,120,120,120,
-839,839,839,839,839,839,839,839,839,839,120,120,120,120,120,120,
-394,394,394,394,394,394,394,394,394,394,394,394,394,120,120,120,
+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,843,843,843,843,843,843,843,844,
+845,845,846,846,846,846,120,120,845,845,845,845,846,846,845,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,843,843,843,843,846,846,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
/* block 177 */
-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,841,842,841,842,842,
-841,841,841,841,841,841,842,841,840,120,120,120,120,120,120,120,
-843,843,843,843,843,843,843,843,843,843,120,120,120,120,120,120,
-120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+848,848,848,848,848,848,848,848,848,848,848,848,848,848,848,848,
+848,848,848,848,848,848,848,848,848,848,848,848,848,848,848,848,
+848,848,848,848,848,848,848,848,848,848,848,848,848,848,848,848,
+849,849,849,850,850,850,850,850,850,850,850,849,849,850,849,850,
+850,851,851,851,848,120,120,120,120,120,120,120,120,120,120,120,
+852,852,852,852,852,852,852,852,852,852,120,120,120,120,120,120,
+398,398,398,398,398,398,398,398,398,398,398,398,398,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
/* block 178 */
-844,844,844,844,844,844,844,844,844,844,844,844,844,844,844,844,
-844,844,844,844,844,844,844,844,844,844,844,120,120,845,845,845,
-846,846,845,845,845,845,846,845,845,845,845,845,120,120,120,120,
-847,847,847,847,847,847,847,847,847,847,848,848,849,849,849,850,
-120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+853,853,853,853,853,853,853,853,853,853,853,853,853,853,853,853,
+853,853,853,853,853,853,853,853,853,853,853,853,853,853,853,853,
+853,853,853,853,853,853,853,853,853,853,853,854,855,854,855,855,
+854,854,854,854,854,854,855,854,853,856,120,120,120,120,120,120,
+857,857,857,857,857,857,857,857,857,857,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
/* block 179 */
-851,851,851,851,851,851,851,851,851,851,851,851,851,851,851,851,
-851,851,851,851,851,851,851,851,851,851,851,851,851,851,851,851,
-851,851,851,851,851,851,851,851,851,851,851,851,852,852,852,853,
-853,853,853,853,853,853,853,853,852,853,853,854,120,120,120,120,
-120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+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,120,120,859,859,859,
+860,860,859,859,859,859,861,859,859,859,859,859,120,120,120,120,
+862,862,862,862,862,862,862,862,862,862,863,863,864,864,864,865,
+858,858,858,858,858,858,858,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
/* block 180 */
+866,866,866,866,866,866,866,866,866,866,866,866,866,866,866,866,
+866,866,866,866,866,866,866,866,866,866,866,866,866,866,866,866,
+866,866,866,866,866,866,866,866,866,866,866,866,867,867,867,868,
+868,868,868,868,868,868,868,868,867,868,868,869,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-855,855,855,855,855,855,855,855,855,855,855,855,855,855,855,855,
-855,855,855,855,855,855,855,855,855,855,855,855,855,855,855,855,
-856,856,856,856,856,856,856,856,856,856,856,856,856,856,856,856,
-856,856,856,856,856,856,856,856,856,856,856,856,856,856,856,856,
-857,857,857,857,857,857,857,857,857,857,858,858,858,858,858,858,
-858,858,858,120,120,120,120,120,120,120,120,120,120,120,120,859,
/* block 181 */
-860,860,860,860,860,860,860,120,120,860,120,120,860,860,860,860,
-860,860,860,860,120,860,860,120,860,860,860,860,860,860,860,860,
-860,860,860,860,860,860,860,860,860,860,860,860,860,860,860,860,
-861,862,862,862,862,862,120,862,862,120,120,863,863,862,863,864,
-862,864,862,863,865,865,865,120,120,120,120,120,120,120,120,120,
-866,866,866,866,866,866,866,866,866,866,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+870,870,870,870,870,870,870,870,870,870,870,870,870,870,870,870,
+870,870,870,870,870,870,870,870,870,870,870,870,870,870,870,870,
+871,871,871,871,871,871,871,871,871,871,871,871,871,871,871,871,
+871,871,871,871,871,871,871,871,871,871,871,871,871,871,871,871,
+872,872,872,872,872,872,872,872,872,872,873,873,873,873,873,873,
+873,873,873,120,120,120,120,120,120,120,120,120,120,120,120,874,
/* block 182 */
+875,875,875,875,875,875,875,120,120,875,120,120,875,875,875,875,
+875,875,875,875,120,875,875,120,875,875,875,875,875,875,875,875,
+875,875,875,875,875,875,875,875,875,875,875,875,875,875,875,875,
+876,877,877,877,877,877,120,877,877,120,120,878,878,877,878,879,
+877,879,877,878,880,880,880,120,120,120,120,120,120,120,120,120,
+881,881,881,881,881,881,881,881,881,881,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-867,867,867,867,867,867,867,867,120,120,867,867,867,867,867,867,
-867,867,867,867,867,867,867,867,867,867,867,867,867,867,867,867,
-867,867,867,867,867,867,867,867,867,867,867,867,867,867,867,867,
-867,868,868,868,869,869,869,869,120,120,869,869,868,868,868,868,
-869,867,870,867,868,120,120,120,120,120,120,120,120,120,120,120,
-120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
/* block 183 */
-871,872,872,872,872,872,872,872,872,872,872,871,871,871,871,871,
-871,871,871,871,871,871,871,871,871,871,871,871,871,871,871,871,
-871,871,871,871,871,871,871,871,871,871,871,871,871,871,871,871,
-871,871,871,872,872,872,872,872,872,873,874,872,872,872,872,875,
-875,875,875,875,875,875,875,872,120,120,120,120,120,120,120,120,
-876,877,877,877,877,877,877,878,878,877,877,877,876,876,876,876,
-876,876,876,876,876,876,876,876,876,876,876,876,876,876,876,876,
-876,876,876,876,876,876,876,876,876,876,876,876,876,876,876,876,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+882,882,882,882,882,882,882,882,120,120,882,882,882,882,882,882,
+882,882,882,882,882,882,882,882,882,882,882,882,882,882,882,882,
+882,882,882,882,882,882,882,882,882,882,882,882,882,882,882,882,
+882,883,883,883,884,884,884,884,120,120,884,884,883,883,883,883,
+884,882,885,882,883,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
/* block 184 */
-876,876,876,876,879,879,879,879,879,879,877,877,877,877,877,877,
-877,877,877,877,877,877,877,878,877,877,880,880,880,876,880,880,
-880,880,880,120,120,120,120,120,120,120,120,120,120,120,120,120,
-120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-881,881,881,881,881,881,881,881,881,881,881,881,881,881,881,881,
-881,881,881,881,881,881,881,881,881,881,881,881,881,881,881,881,
-881,881,881,881,881,881,881,881,881,881,881,881,881,881,881,881,
-881,881,881,881,881,881,881,881,881,120,120,120,120,120,120,120,
+886,887,887,887,887,887,887,887,887,887,887,886,886,886,886,886,
+886,886,886,886,886,886,886,886,886,886,886,886,886,886,886,886,
+886,886,886,886,886,886,886,886,886,886,886,886,886,886,886,886,
+886,886,886,887,887,887,887,887,887,888,889,887,887,887,887,890,
+890,890,890,890,890,890,890,887,120,120,120,120,120,120,120,120,
+891,892,892,892,892,892,892,893,893,892,892,892,891,891,891,891,
+891,891,891,891,891,891,891,891,891,891,891,891,891,891,891,891,
+891,891,891,891,891,891,891,891,891,891,891,891,891,891,891,891,
/* block 185 */
-882,882,882,882,882,882,882,882,882,120,882,882,882,882,882,882,
-882,882,882,882,882,882,882,882,882,882,882,882,882,882,882,882,
-882,882,882,882,882,882,882,882,882,882,882,882,882,882,882,883,
-884,884,884,884,884,884,884,120,884,884,884,884,884,884,883,884,
-882,885,885,885,885,885,120,120,120,120,120,120,120,120,120,120,
-886,886,886,886,886,886,886,886,886,886,887,887,887,887,887,887,
-887,887,887,887,887,887,887,887,887,887,887,887,887,120,120,120,
-888,888,889,889,889,889,889,889,889,889,889,889,889,889,889,889,
+891,891,891,891,894,894,894,894,894,894,892,892,892,892,892,892,
+892,892,892,892,892,892,892,893,892,892,895,895,895,891,895,895,
+895,895,895,120,120,120,120,120,120,120,120,120,120,120,120,120,
+370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,
+896,896,896,896,896,896,896,896,896,896,896,896,896,896,896,896,
+896,896,896,896,896,896,896,896,896,896,896,896,896,896,896,896,
+896,896,896,896,896,896,896,896,896,896,896,896,896,896,896,896,
+896,896,896,896,896,896,896,896,896,120,120,120,120,120,120,120,
/* block 186 */
-889,889,889,889,889,889,889,889,889,889,889,889,889,889,889,889,
-120,120,890,890,890,890,890,890,890,890,890,890,890,890,890,890,
-890,890,890,890,890,890,890,890,120,891,890,890,890,890,890,890,
-890,891,890,890,891,890,890,120,120,120,120,120,120,120,120,120,
+897,897,897,897,897,897,897,897,897,120,897,897,897,897,897,897,
+897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,
+897,897,897,897,897,897,897,897,897,897,897,897,897,897,897,898,
+899,899,899,899,899,899,899,120,899,899,899,899,899,899,898,899,
+897,900,900,900,900,900,120,120,120,120,120,120,120,120,120,120,
+901,901,901,901,901,901,901,901,901,901,902,902,902,902,902,902,
+902,902,902,902,902,902,902,902,902,902,902,902,902,120,120,120,
+903,903,904,904,904,904,904,904,904,904,904,904,904,904,904,904,
+
+/* block 187 */
+904,904,904,904,904,904,904,904,904,904,904,904,904,904,904,904,
+120,120,905,905,905,905,905,905,905,905,905,905,905,905,905,905,
+905,905,905,905,905,905,905,905,120,906,905,905,905,905,905,905,
+905,906,905,905,906,905,905,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-/* block 187 */
-892,892,892,892,892,892,892,120,892,892,120,892,892,892,892,892,
-892,892,892,892,892,892,892,892,892,892,892,892,892,892,892,892,
-892,892,892,892,892,892,892,892,892,892,892,892,892,892,892,892,
-892,893,893,893,893,893,893,120,120,120,893,120,893,893,120,893,
-893,893,893,893,893,893,894,893,120,120,120,120,120,120,120,120,
-895,895,895,895,895,895,895,895,895,895,120,120,120,120,120,120,
-896,896,896,896,896,896,120,896,896,120,896,896,896,896,896,896,
-896,896,896,896,896,896,896,896,896,896,896,896,896,896,896,896,
-
/* block 188 */
-896,896,896,896,896,896,896,896,896,896,897,897,897,897,897,120,
-898,898,120,897,897,898,897,898,896,120,120,120,120,120,120,120,
-899,899,899,899,899,899,899,899,899,899,120,120,120,120,120,120,
+907,907,907,907,907,907,907,120,907,907,120,907,907,907,907,907,
+907,907,907,907,907,907,907,907,907,907,907,907,907,907,907,907,
+907,907,907,907,907,907,907,907,907,907,907,907,907,907,907,907,
+907,908,908,908,908,908,908,120,120,120,908,120,908,908,120,908,
+908,908,908,908,908,908,909,908,120,120,120,120,120,120,120,120,
+910,910,910,910,910,910,910,910,910,910,120,120,120,120,120,120,
+911,911,911,911,911,911,120,911,911,120,911,911,911,911,911,911,
+911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,
+
+/* block 189 */
+911,911,911,911,911,911,911,911,911,911,912,912,912,912,912,120,
+913,913,120,912,912,913,912,913,911,120,120,120,120,120,120,120,
+914,914,914,914,914,914,914,914,914,914,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-/* block 189 */
+/* block 190 */
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-900,900,900,900,900,900,900,900,900,900,900,900,900,900,900,900,
-900,900,900,901,901,902,902,903,903,120,120,120,120,120,120,120,
+915,915,915,915,915,915,915,915,915,915,915,915,915,915,915,915,
+915,915,915,916,916,917,917,918,918,120,120,120,120,120,120,120,
-/* block 190 */
+/* block 191 */
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-590,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-904,904,904,904,904,904,904,904,904,904,904,904,904,904,904,904,
-293,293,904,293,904,295,295,295,295,295,295,295,295,296,296,296,
-296,295,295,295,295,295,295,295,295,295,295,295,295,295,295,295,
-295,295,120,120,120,120,120,120,120,120,120,120,120,120,120,905,
-
-/* block 191 */
-906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,
-906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,
-906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,
-906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,
-906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,
-906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,
-906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,
-906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,
+595,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+919,919,919,919,919,919,919,919,919,919,919,919,919,919,919,919,
+295,295,919,295,919,297,297,297,297,297,297,297,297,298,298,298,
+298,297,297,297,297,297,297,297,297,297,297,297,297,297,297,297,
+297,297,120,120,120,120,120,120,120,120,120,120,120,120,120,920,
/* block 192 */
-906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,
-906,906,906,906,906,906,906,906,906,906,120,120,120,120,120,120,
+921,921,921,921,921,921,921,921,921,921,921,921,921,921,921,921,
+921,921,921,921,921,921,921,921,921,921,921,921,921,921,921,921,
+921,921,921,921,921,921,921,921,921,921,921,921,921,921,921,921,
+921,921,921,921,921,921,921,921,921,921,921,921,921,921,921,921,
+921,921,921,921,921,921,921,921,921,921,921,921,921,921,921,921,
+921,921,921,921,921,921,921,921,921,921,921,921,921,921,921,921,
+921,921,921,921,921,921,921,921,921,921,921,921,921,921,921,921,
+921,921,921,921,921,921,921,921,921,921,921,921,921,921,921,921,
+
+/* block 193 */
+921,921,921,921,921,921,921,921,921,921,921,921,921,921,921,921,
+921,921,921,921,921,921,921,921,921,921,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
@@ -3648,108 +3684,118 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-/* block 193 */
-907,907,907,907,907,907,907,907,907,907,907,907,907,907,907,907,
-907,907,907,907,907,907,907,907,907,907,907,907,907,907,907,907,
-907,907,907,907,907,907,907,907,907,907,907,907,907,907,907,907,
-907,907,907,907,907,907,907,907,907,907,907,907,907,907,907,907,
-907,907,907,907,907,907,907,907,907,907,907,907,907,907,907,907,
-907,907,907,907,907,907,907,907,907,907,907,907,907,907,907,907,
-907,907,907,907,907,907,907,907,907,907,907,907,907,907,907,120,
-908,908,908,908,908,120,120,120,120,120,120,120,120,120,120,120,
-
/* block 194 */
-906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,
-906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,
-906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,
-906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,
-906,906,906,906,120,120,120,120,120,120,120,120,120,120,120,120,
-120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+922,922,922,922,922,922,922,922,922,922,922,922,922,922,922,922,
+922,922,922,922,922,922,922,922,922,922,922,922,922,922,922,922,
+922,922,922,922,922,922,922,922,922,922,922,922,922,922,922,922,
+922,922,922,922,922,922,922,922,922,922,922,922,922,922,922,922,
+922,922,922,922,922,922,922,922,922,922,922,922,922,922,922,922,
+922,922,922,922,922,922,922,922,922,922,922,922,922,922,922,922,
+922,922,922,922,922,922,922,922,922,922,922,922,922,922,922,120,
+923,923,923,923,923,120,120,120,120,120,120,120,120,120,120,120,
/* block 195 */
-909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,
-909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,
-909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,
-909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,
-909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,
-909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,
-909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,
-909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,
-
-/* block 196 */
-909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,
-909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,
-909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,120,
-910,910,910,910,910,910,910,910,910,120,120,120,120,120,120,120,
+921,921,921,921,921,921,921,921,921,921,921,921,921,921,921,921,
+921,921,921,921,921,921,921,921,921,921,921,921,921,921,921,921,
+921,921,921,921,921,921,921,921,921,921,921,921,921,921,921,921,
+921,921,921,921,921,921,921,921,921,921,921,921,921,921,921,921,
+921,921,921,921,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 196 */
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+924,924,924,924,924,924,924,924,924,924,924,924,924,924,924,924,
+924,924,924,924,924,924,924,924,924,924,924,924,924,924,924,924,
+924,924,924,924,924,924,924,924,924,924,924,924,924,924,924,924,
+924,924,924,924,924,924,924,924,924,924,924,924,924,924,924,924,
+924,924,924,924,924,924,924,924,924,924,924,924,924,924,924,924,
+924,924,924,924,924,924,924,924,924,924,924,924,924,924,924,924,
+924,925,925,120,120,120,120,120,120,120,120,120,120,120,120,120,
/* block 197 */
-911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,
-911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,
-911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,
-911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,
-911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,
-911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,
-911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,
-911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,
+926,926,926,926,926,926,926,926,926,926,926,926,926,926,926,926,
+926,926,926,926,926,926,926,926,926,926,926,926,926,926,926,926,
+926,926,926,926,926,926,926,926,926,926,926,926,926,926,926,926,
+926,926,926,926,926,926,926,926,926,926,926,926,926,926,926,926,
+926,926,926,926,926,926,926,926,926,926,926,926,926,926,926,926,
+926,926,926,926,926,926,926,926,926,926,926,926,926,926,926,926,
+926,926,926,926,926,926,926,926,926,926,926,926,926,926,926,926,
+926,926,926,926,926,926,926,926,926,926,926,926,926,926,926,926,
/* block 198 */
-911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,
-911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,
-911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,
-911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,
-911,911,911,911,911,911,911,120,120,120,120,120,120,120,120,120,
+926,926,926,926,926,926,926,926,926,926,926,926,926,926,926,926,
+926,926,926,926,926,926,926,926,926,926,926,926,926,926,926,926,
+926,926,926,926,926,926,926,926,926,926,926,926,926,926,926,120,
+927,927,927,927,927,927,927,927,927,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
/* block 199 */
-601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
-601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
-601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
-601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
-601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
-601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
-601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
-601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
+928,928,928,928,928,928,928,928,928,928,928,928,928,928,928,928,
+928,928,928,928,928,928,928,928,928,928,928,928,928,928,928,928,
+928,928,928,928,928,928,928,928,928,928,928,928,928,928,928,928,
+928,928,928,928,928,928,928,928,928,928,928,928,928,928,928,928,
+928,928,928,928,928,928,928,928,928,928,928,928,928,928,928,928,
+928,928,928,928,928,928,928,928,928,928,928,928,928,928,928,928,
+928,928,928,928,928,928,928,928,928,928,928,928,928,928,928,928,
+928,928,928,928,928,928,928,928,928,928,928,928,928,928,928,928,
/* block 200 */
-601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
-601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
-601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
-601,601,601,601,601,601,601,601,601,120,120,120,120,120,120,120,
-912,912,912,912,912,912,912,912,912,912,912,912,912,912,912,912,
-912,912,912,912,912,912,912,912,912,912,912,912,912,912,912,120,
-913,913,913,913,913,913,913,913,913,913,120,120,120,120,914,914,
-120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-
-/* block 201 */
+928,928,928,928,928,928,928,928,928,928,928,928,928,928,928,928,
+928,928,928,928,928,928,928,928,928,928,928,928,928,928,928,928,
+928,928,928,928,928,928,928,928,928,928,928,928,928,928,928,928,
+928,928,928,928,928,928,928,928,928,928,928,928,928,928,928,928,
+928,928,928,928,928,928,928,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-915,915,915,915,915,915,915,915,915,915,915,915,915,915,915,915,
-915,915,915,915,915,915,915,915,915,915,915,915,915,915,120,120,
-916,916,916,916,916,917,120,120,120,120,120,120,120,120,120,120,
+
+/* block 201 */
+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,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,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,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,606,606,606,606,606,606,606,606,
/* block 202 */
-918,918,918,918,918,918,918,918,918,918,918,918,918,918,918,918,
-918,918,918,918,918,918,918,918,918,918,918,918,918,918,918,918,
-918,918,918,918,918,918,918,918,918,918,918,918,918,918,918,918,
-919,919,919,919,919,919,919,920,920,920,920,920,921,921,921,921,
-922,922,922,922,920,921,120,120,120,120,120,120,120,120,120,120,
-923,923,923,923,923,923,923,923,923,923,120,924,924,924,924,924,
-924,924,120,918,918,918,918,918,918,918,918,918,918,918,918,918,
-918,918,918,918,918,918,918,918,120,120,120,120,120,918,918,918,
+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,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,120,120,120,120,120,120,120,
+929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,
+929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,120,
+930,930,930,930,930,930,930,930,930,930,120,120,120,120,931,931,
+932,932,932,932,932,932,932,932,932,932,932,932,932,932,932,932,
/* block 203 */
-918,918,918,918,918,918,918,918,918,918,918,918,918,918,918,918,
+932,932,932,932,932,932,932,932,932,932,932,932,932,932,932,932,
+932,932,932,932,932,932,932,932,932,932,932,932,932,932,932,932,
+932,932,932,932,932,932,932,932,932,932,932,932,932,932,932,932,
+932,932,932,932,932,932,932,932,932,932,932,932,932,932,932,120,
+933,933,933,933,933,933,933,933,933,933,120,120,120,120,120,120,
+934,934,934,934,934,934,934,934,934,934,934,934,934,934,934,934,
+934,934,934,934,934,934,934,934,934,934,934,934,934,934,120,120,
+935,935,935,935,935,936,120,120,120,120,120,120,120,120,120,120,
+
+/* block 204 */
+937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
+937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
+937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
+938,938,938,938,938,938,938,939,939,939,939,939,940,940,940,940,
+941,941,941,941,939,940,120,120,120,120,120,120,120,120,120,120,
+942,942,942,942,942,942,942,942,942,942,120,943,943,943,943,943,
+943,943,120,937,937,937,937,937,937,937,937,937,937,937,937,937,
+937,937,937,937,937,937,937,937,120,120,120,120,120,937,937,937,
+
+/* block 205 */
+937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
@@ -3758,19 +3804,19 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-/* block 204 */
+/* block 206 */
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-925,925,925,925,925,925,925,925,925,925,925,925,925,925,925,925,
-925,925,925,925,925,925,925,925,925,925,925,925,925,925,925,925,
-926,926,926,926,926,926,926,926,926,926,926,926,926,926,926,926,
-926,926,926,926,926,926,926,926,926,926,926,926,926,926,926,926,
+944,944,944,944,944,944,944,944,944,944,944,944,944,944,944,944,
+944,944,944,944,944,944,944,944,944,944,944,944,944,944,944,944,
+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,
-/* block 205 */
-927,927,927,927,927,927,927,927,927,927,927,927,927,927,927,927,
-927,927,927,927,927,927,927,928,928,928,928,120,120,120,120,120,
+/* block 207 */
+946,946,946,946,946,946,946,946,946,946,946,946,946,946,946,946,
+946,946,946,946,946,946,946,947,947,947,947,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
@@ -3778,68 +3824,68 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-/* block 206 */
-929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,
-929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,
-929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,
-929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,
-929,929,929,929,929,929,929,929,929,929,929,120,120,120,120,930,
-929,931,931,931,931,931,931,931,931,931,931,931,931,931,931,931,
-931,931,931,931,931,931,931,931,931,931,931,931,931,931,931,931,
-931,931,931,931,931,931,931,931,931,931,931,931,931,931,931,931,
+/* block 208 */
+948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,
+948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,
+948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,
+948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,
+948,948,948,948,948,948,948,948,948,948,948,120,120,120,120,949,
+948,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,950,950,950,950,
+950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
-/* block 207 */
-931,931,931,931,931,931,931,931,120,120,120,120,120,120,120,930,
-930,930,930,932,932,932,932,932,932,932,932,932,932,932,932,932,
+/* block 209 */
+950,950,950,950,950,950,950,950,120,120,120,120,120,120,120,949,
+949,949,949,951,951,951,951,951,951,951,951,951,951,951,951,951,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-933,934, 5,111,935,120,120,120,120,120,120,120,120,120,120,120,
-936,936,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-
-/* block 208 */
-937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
-937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
-937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
-937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
-937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
-937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
-937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
-937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
-
-/* block 209 */
-937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
-937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
-937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
-937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
-937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
-937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
-937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
-937,937,937,937,937,937,937,937,120,120,120,120,120,120,120,120,
+952,953,954,562,955,120,120,120,120,120,120,120,120,120,120,120,
+956,956,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
/* block 210 */
-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,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,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,938,938,938,938,938,938,938,
-938,938,938,938,938,938,938,938,938,938,938,938,938,938,938,938,
+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,
+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,
+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,
+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,
/* block 211 */
-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,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,938,938,938,938,938,938,938,938,938,938,
-938,938,938,938,938,938,120,120,120,120,120,120,120,120,120,120,
+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,
+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,
+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,
+957,957,957,957,957,957,957,957,957,957,957,957,957,957,957,957,
+957,957,957,957,957,957,957,957,120,120,120,120,120,120,120,120,
+
+/* block 212 */
+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,
+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,
+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,
+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,
+
+/* block 213 */
+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,
+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,
+958,958,958,958,958,958,958,958,958,958,958,958,958,958,958,958,
+958,958,958,958,958,958,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-/* block 212 */
-937,937,937,937,937,937,937,937,937,120,120,120,120,120,120,120,
+/* block 214 */
+957,957,957,957,957,957,957,957,957,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
@@ -3848,77 +3894,107 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-/* block 213 */
-578,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
-573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
-573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
-573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
-573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
-573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
-573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
-573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
-
-/* block 214 */
-573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
-573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
-573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
-573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
-573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
-573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
-573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
-573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
-
/* block 215 */
-573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
-573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-573,573,573,120,120,120,120,120,120,120,120,120,120,120,120,120,
-120,120,120,120,578,578,578,578,120,120,120,120,120,120,120,120,
-939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+584,584,584,584,120,584,584,584,584,584,584,584,120,584,584,120,
/* block 216 */
-939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,
-939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,
-939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,
-939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,
-939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,
-939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,
-939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,
-939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,
+583,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
+578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
+578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
+578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
+578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
+578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
+578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
+578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
/* block 217 */
-939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,
-939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,
-939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,
-939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,
-939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,
-939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,
-939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,
-939,939,939,939,939,939,939,939,939,939,939,939,120,120,120,120,
+578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
+578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
+578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
+578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
+578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
+578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
+578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
+578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
/* block 218 */
-940,940,940,940,940,940,940,940,940,940,940,940,940,940,940,940,
-940,940,940,940,940,940,940,940,940,940,940,940,940,940,940,940,
-940,940,940,940,940,940,940,940,940,940,940,940,940,940,940,940,
-940,940,940,940,940,940,940,940,940,940,940,940,940,940,940,940,
-940,940,940,940,940,940,940,940,940,940,940,940,940,940,940,940,
-940,940,940,940,940,940,940,940,940,940,940,940,940,940,940,940,
-940,940,940,940,940,940,940,940,940,940,940,120,120,120,120,120,
-940,940,940,940,940,940,940,940,940,940,940,940,940,120,120,120,
+578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
+578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
+583,583,583,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+578,578,578,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,583,583,583,583,120,120,120,120,120,120,120,120,
+959,959,959,959,959,959,959,959,959,959,959,959,959,959,959,959,
/* block 219 */
-940,940,940,940,940,940,940,940,940,120,120,120,120,120,120,120,
-940,940,940,940,940,940,940,940,940,940,120,120,941,942,942,943,
-944,944,944,944,120,120,120,120,120,120,120,120,120,120,120,120,
+959,959,959,959,959,959,959,959,959,959,959,959,959,959,959,959,
+959,959,959,959,959,959,959,959,959,959,959,959,959,959,959,959,
+959,959,959,959,959,959,959,959,959,959,959,959,959,959,959,959,
+959,959,959,959,959,959,959,959,959,959,959,959,959,959,959,959,
+959,959,959,959,959,959,959,959,959,959,959,959,959,959,959,959,
+959,959,959,959,959,959,959,959,959,959,959,959,959,959,959,959,
+959,959,959,959,959,959,959,959,959,959,959,959,959,959,959,959,
+959,959,959,959,959,959,959,959,959,959,959,959,959,959,959,959,
+
+/* block 220 */
+959,959,959,959,959,959,959,959,959,959,959,959,959,959,959,959,
+959,959,959,959,959,959,959,959,959,959,959,959,959,959,959,959,
+959,959,959,959,959,959,959,959,959,959,959,959,959,959,959,959,
+959,959,959,959,959,959,959,959,959,959,959,959,959,959,959,959,
+959,959,959,959,959,959,959,959,959,959,959,959,959,959,959,959,
+959,959,959,959,959,959,959,959,959,959,959,959,959,959,959,959,
+959,959,959,959,959,959,959,959,959,959,959,959,959,959,959,959,
+959,959,959,959,959,959,959,959,959,959,959,959,120,120,120,120,
+
+/* block 221 */
+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,120,120,120,120,120,
+960,960,960,960,960,960,960,960,960,960,960,960,960,120,120,120,
+
+/* block 222 */
+960,960,960,960,960,960,960,960,960,120,120,120,120,120,120,120,
+960,960,960,960,960,960,960,960,960,960,120,120,961,962,962,963,
+964,964,964,964,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-/* block 220 */
+/* block 223 */
+113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
+113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
+113,113,113,113,113,113,113,113,113,113,113,113,113,113,120,120,
+113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
+113,113,113,113,113,113,113,120,120,120,120,120,120,120,120,120,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+
+/* block 224 */
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 225 */
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
@@ -3928,37 +4004,37 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20,120,120,120,120,120,120,120,120,120,120,
-/* block 221 */
+/* block 226 */
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20,120,120, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
- 20, 20, 20, 20, 20,945,946,113,113,113, 20, 20, 20,946,945,945,
-945,945,945, 24, 24, 24, 24, 24, 24, 24, 24,113,113,113,113,113,
+ 20, 20, 20, 20, 20,965,966,113,113,113, 20, 20, 20,966,965,965,
+965,965,965, 24, 24, 24, 24, 24, 24, 24, 24,113,113,113,113,113,
-/* block 222 */
+/* block 227 */
113,113,113, 20, 20,113,113,113,113,113,113,113, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20,113,113,113,113, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
- 20, 20, 20, 20, 20, 20, 20, 20, 20,120,120,120,120,120,120,120,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-/* block 223 */
-685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,
-685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,
-685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,
-685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,
-685,685,947,947,947,685,120,120,120,120,120,120,120,120,120,120,
+/* block 228 */
+692,692,692,692,692,692,692,692,692,692,692,692,692,692,692,692,
+692,692,692,692,692,692,692,692,692,692,692,692,692,692,692,692,
+692,692,692,692,692,692,692,692,692,692,692,692,692,692,692,692,
+692,692,692,692,692,692,692,692,692,692,692,692,692,692,692,692,
+692,692,967,967,967,692,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-/* block 224 */
+/* block 229 */
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
@@ -3968,187 +4044,207 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25,120,120,120,120,120,120,120,120,120,120,120,120,
-/* block 225 */
+/* block 230 */
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20,120,120,120,120,120,120,120,120,120,
-582,582,582,582,582,582,582,582,582,582,582,582,582,582,582,582,
-582,582, 25, 25, 25, 25, 25, 25, 25,120,120,120,120,120,120,120,
+587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,
+587,587, 25, 25, 25, 25, 25, 25, 25,120,120,120,120,120,120,120,
-/* block 226 */
-513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,
-513,513,513,513,513,513,513,513,513,513,514,514,514,514,514,514,
-514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,
-514,514,514,514,513,513,513,513,513,513,513,513,513,513,513,513,
-513,513,513,513,513,513,513,513,513,513,513,513,513,513,514,514,
-514,514,514,514,514,120,514,514,514,514,514,514,514,514,514,514,
-514,514,514,514,514,514,514,514,513,513,513,513,513,513,513,513,
-513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,
+/* block 231 */
+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,519,519,519,519,
+519,519,519,519,519,519,519,519,519,519,519,519,519,519,519,519,
+519,519,519,519,518,518,518,518,518,518,518,518,518,518,518,518,
+518,518,518,518,518,518,518,518,518,518,518,518,518,518,519,519,
+519,519,519,519,519,120,519,519,519,519,519,519,519,519,519,519,
+519,519,519,519,519,519,519,519,518,518,518,518,518,518,518,518,
+518,518,518,518,518,518,518,518,518,518,518,518,518,518,518,518,
-/* block 227 */
-513,513,514,514,514,514,514,514,514,514,514,514,514,514,514,514,
-514,514,514,514,514,514,514,514,514,514,514,514,513,120,513,513,
-120,120,513,120,120,513,513,120,120,513,513,513,513,120,513,513,
-513,513,513,513,513,513,514,514,514,514,120,514,120,514,514,514,
-514,514,514,514,120,514,514,514,514,514,514,514,514,514,514,514,
-513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,
-513,513,513,513,513,513,513,513,513,513,514,514,514,514,514,514,
-514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,
+/* block 232 */
+518,518,519,519,519,519,519,519,519,519,519,519,519,519,519,519,
+519,519,519,519,519,519,519,519,519,519,519,519,518,120,518,518,
+120,120,518,120,120,518,518,120,120,518,518,518,518,120,518,518,
+518,518,518,518,518,518,519,519,519,519,120,519,120,519,519,519,
+519,519,519,519,120,519,519,519,519,519,519,519,519,519,519,519,
+518,518,518,518,518,518,518,518,518,518,518,518,518,518,518,518,
+518,518,518,518,518,518,518,518,518,518,519,519,519,519,519,519,
+519,519,519,519,519,519,519,519,519,519,519,519,519,519,519,519,
-/* block 228 */
-514,514,514,514,513,513,120,513,513,513,513,120,120,513,513,513,
-513,513,513,513,513,120,513,513,513,513,513,513,513,120,514,514,
-514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,
-514,514,514,514,514,514,514,514,513,513,120,513,513,513,513,120,
-513,513,513,513,513,120,513,120,120,120,513,513,513,513,513,513,
-513,120,514,514,514,514,514,514,514,514,514,514,514,514,514,514,
-514,514,514,514,514,514,514,514,514,514,514,514,513,513,513,513,
-513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,
+/* block 233 */
+519,519,519,519,518,518,120,518,518,518,518,120,120,518,518,518,
+518,518,518,518,518,120,518,518,518,518,518,518,518,120,519,519,
+519,519,519,519,519,519,519,519,519,519,519,519,519,519,519,519,
+519,519,519,519,519,519,519,519,518,518,120,518,518,518,518,120,
+518,518,518,518,518,120,518,120,120,120,518,518,518,518,518,518,
+518,120,519,519,519,519,519,519,519,519,519,519,519,519,519,519,
+519,519,519,519,519,519,519,519,519,519,519,519,518,518,518,518,
+518,518,518,518,518,518,518,518,518,518,518,518,518,518,518,518,
-/* block 229 */
-513,513,513,513,513,513,514,514,514,514,514,514,514,514,514,514,
-514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,
-513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,
-513,513,513,513,513,513,513,513,513,513,514,514,514,514,514,514,
-514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,
-514,514,514,514,513,513,513,513,513,513,513,513,513,513,513,513,
-513,513,513,513,513,513,513,513,513,513,513,513,513,513,514,514,
-514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,
+/* block 234 */
+518,518,518,518,518,518,519,519,519,519,519,519,519,519,519,519,
+519,519,519,519,519,519,519,519,519,519,519,519,519,519,519,519,
+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,519,519,519,519,
+519,519,519,519,519,519,519,519,519,519,519,519,519,519,519,519,
+519,519,519,519,518,518,518,518,518,518,518,518,518,518,518,518,
+518,518,518,518,518,518,518,518,518,518,518,518,518,518,519,519,
+519,519,519,519,519,519,519,519,519,519,519,519,519,519,519,519,
-/* block 230 */
-514,514,514,514,514,514,514,514,513,513,513,513,513,513,513,513,
-513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,
-513,513,514,514,514,514,514,514,514,514,514,514,514,514,514,514,
-514,514,514,514,514,514,514,514,514,514,514,514,513,513,513,513,
-513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,
-513,513,513,513,513,513,514,514,514,514,514,514,514,514,514,514,
-514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,
-513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,
+/* block 235 */
+519,519,519,519,519,519,519,519,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,519,519,519,519,519,519,519,519,519,519,519,519,
+519,519,519,519,519,519,519,519,519,519,519,519,518,518,518,518,
+518,518,518,518,518,518,518,518,518,518,518,518,518,518,518,518,
+518,518,518,518,518,518,519,519,519,519,519,519,519,519,519,519,
+519,519,519,519,519,519,519,519,519,519,519,519,519,519,519,519,
+518,518,518,518,518,518,518,518,518,518,518,518,518,518,518,518,
-/* block 231 */
-513,513,513,513,513,513,513,513,513,513,514,514,514,514,514,514,
-514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,
-514,514,514,514,514,514,120,120,513,513,513,513,513,513,513,513,
-513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,
-513, 9,514,514,514,514,514,514,514,514,514,514,514,514,514,514,
-514,514,514,514,514,514,514,514,514,514,514, 9,514,514,514,514,
-514,514,513,513,513,513,513,513,513,513,513,513,513,513,513,513,
-513,513,513,513,513,513,513,513,513,513,513, 9,514,514,514,514,
+/* block 236 */
+518,518,518,518,518,518,518,518,518,518,519,519,519,519,519,519,
+519,519,519,519,519,519,519,519,519,519,519,519,519,519,519,519,
+519,519,519,519,519,519,120,120,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, 9,519,519,519,519,519,519,519,519,519,519,519,519,519,519,
+519,519,519,519,519,519,519,519,519,519,519, 9,519,519,519,519,
+519,519,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, 9,519,519,519,519,
-/* block 232 */
-514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,
-514,514,514,514,514, 9,514,514,514,514,514,514,513,513,513,513,
-513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,
-513,513,513,513,513, 9,514,514,514,514,514,514,514,514,514,514,
-514,514,514,514,514,514,514,514,514,514,514,514,514,514,514, 9,
-514,514,514,514,514,514,513,513,513,513,513,513,513,513,513,513,
-513,513,513,513,513,513,513,513,513,513,513,513,513,513,513, 9,
-514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,
+/* block 237 */
+519,519,519,519,519,519,519,519,519,519,519,519,519,519,519,519,
+519,519,519,519,519, 9,519,519,519,519,519,519,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, 9,519,519,519,519,519,519,519,519,519,519,
+519,519,519,519,519,519,519,519,519,519,519,519,519,519,519, 9,
+519,519,519,519,519,519,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, 9,
+519,519,519,519,519,519,519,519,519,519,519,519,519,519,519,519,
-/* block 233 */
-514,514,514,514,514,514,514,514,514, 9,514,514,514,514,514,514,
-513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,
-513,513,513,513,513,513,513,513,513, 9,514,514,514,514,514,514,
-514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,
-514,514,514, 9,514,514,514,514,514,514,513,514,120,120, 11, 11,
+/* block 238 */
+519,519,519,519,519,519,519,519,519, 9,519,519,519,519,519,519,
+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, 9,519,519,519,519,519,519,
+519,519,519,519,519,519,519,519,519,519,519,519,519,519,519,519,
+519,519,519, 9,519,519,519,519,519,519,518,519,120,120, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
-/* block 234 */
-948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,
-948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,
-948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,
-948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,
-948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,
-948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,
-948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,
-948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,
+/* block 239 */
+968,968,968,968,968,968,968,968,968,968,968,968,968,968,968,968,
+968,968,968,968,968,968,968,968,968,968,968,968,968,968,968,968,
+968,968,968,968,968,968,968,968,968,968,968,968,968,968,968,968,
+968,968,968,968,968,968,968,968,968,968,968,968,968,968,968,968,
+968,968,968,968,968,968,968,968,968,968,968,968,968,968,968,968,
+968,968,968,968,968,968,968,968,968,968,968,968,968,968,968,968,
+968,968,968,968,968,968,968,968,968,968,968,968,968,968,968,968,
+968,968,968,968,968,968,968,968,968,968,968,968,968,968,968,968,
-/* block 235 */
-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,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,949,948,948,948,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,949,949,949,949,949,949,949,949,949,949,
-949,949,949,949,949,949,949,949,949,949,949,949,949,948,948,948,
-948,948,948,948,948,949,948,948,948,948,948,948,948,948,948,948,
+/* block 240 */
+969,969,969,969,969,969,969,969,969,969,969,969,969,969,969,969,
+969,969,969,969,969,969,969,969,969,969,969,969,969,969,969,969,
+969,969,969,969,969,969,969,969,969,969,969,969,969,969,969,969,
+969,969,969,969,969,969,969,968,968,968,968,969,969,969,969,969,
+969,969,969,969,969,969,969,969,969,969,969,969,969,969,969,969,
+969,969,969,969,969,969,969,969,969,969,969,969,969,969,969,969,
+969,969,969,969,969,969,969,969,969,969,969,969,969,968,968,968,
+968,968,968,968,968,969,968,968,968,968,968,968,968,968,968,968,
-/* block 236 */
-948,948,948,948,949,948,948,950,950,950,950,950,120,120,120,120,
-120,120,120,120,120,120,120,120,120,120,120,949,949,949,949,949,
-120,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+/* block 241 */
+968,968,968,968,969,968,968,970,970,970,970,970,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,969,969,969,969,969,
+120,969,969,969,969,969,969,969,969,969,969,969,969,969,969,969,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-/* block 237 */
-951,951,951,951,951,951,951,120,951,951,951,951,951,951,951,951,
-951,951,951,951,951,951,951,951,951,120,120,951,951,951,951,951,
-951,951,120,951,951,120,951,951,951,951,951,120,120,120,120,120,
+/* block 242 */
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 22, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-/* block 238 */
-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,120,120,120,
-953,953,953,953,953,953,953,954,954,954,954,954,954,954,120,120,
-955,955,955,955,955,955,955,955,955,955,120,120,120,120,952,956,
+/* block 243 */
+971,971,971,971,971,971,971,120,971,971,971,971,971,971,971,971,
+971,971,971,971,971,971,971,971,971,120,120,971,971,971,971,971,
+971,971,120,971,971,120,971,971,971,971,971,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-/* block 239 */
+/* block 244 */
+972,972,972,972,972,972,972,972,972,972,972,972,972,972,972,972,
+972,972,972,972,972,972,972,972,972,972,972,972,972,972,972,972,
+972,972,972,972,972,972,972,972,972,972,972,972,972,120,120,120,
+973,973,973,973,973,973,973,974,974,974,974,974,974,974,120,120,
+975,975,975,975,975,975,975,975,975,975,120,120,120,120,972,976,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 245 */
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-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,
-957,957,957,957,957,957,957,957,957,957,957,957,958,958,958,958,
-959,959,959,959,959,959,959,959,959,959,120,120,120,120,120,960,
+977,977,977,977,977,977,977,977,977,977,977,977,977,977,977,977,
+977,977,977,977,977,977,977,977,977,977,977,977,977,977,978,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+979,979,979,979,979,979,979,979,979,979,979,979,979,979,979,979,
+979,979,979,979,979,979,979,979,979,979,979,979,979,979,979,979,
+979,979,979,979,979,979,979,979,979,979,979,979,980,980,980,980,
+981,981,981,981,981,981,981,981,981,981,120,120,120,120,120,982,
-/* block 240 */
-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 246 */
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+361,361,361,361,361,361,361,120,361,361,361,361,120,361,361,120,
+361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,120,
-/* block 241 */
-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,120,120,962,962,962,962,962,962,962,962,962,
-963,963,963,963,963,963,963,120,120,120,120,120,120,120,120,120,
+/* block 247 */
+983,983,983,983,983,983,983,983,983,983,983,983,983,983,983,983,
+983,983,983,983,983,983,983,983,983,983,983,983,983,983,983,983,
+983,983,983,983,983,983,983,983,983,983,983,983,983,983,983,983,
+983,983,983,983,983,983,983,983,983,983,983,983,983,983,983,983,
+983,983,983,983,983,983,983,983,983,983,983,983,983,983,983,983,
+983,983,983,983,983,983,983,983,983,983,983,983,983,983,983,983,
+983,983,983,983,983,983,983,983,983,983,983,983,983,983,983,983,
+983,983,983,983,983,983,983,983,983,983,983,983,983,983,983,983,
+
+/* block 248 */
+983,983,983,983,983,983,983,983,983,983,983,983,983,983,983,983,
+983,983,983,983,983,983,983,983,983,983,983,983,983,983,983,983,
+983,983,983,983,983,983,983,983,983,983,983,983,983,983,983,983,
+983,983,983,983,983,983,983,983,983,983,983,983,983,983,983,983,
+983,983,983,983,983,120,120,984,984,984,984,984,984,984,984,984,
+985,985,985,985,985,985,985,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-/* block 242 */
-964,964,964,964,964,964,964,964,964,964,964,964,964,964,964,964,
-964,964,964,964,964,964,964,964,964,964,964,964,964,964,964,964,
-964,964,965,965,965,965,965,965,965,965,965,965,965,965,965,965,
-965,965,965,965,965,965,965,965,965,965,965,965,965,965,965,965,
-965,965,965,965,966,966,966,966,966,966,966,967,120,120,120,120,
-968,968,968,968,968,968,968,968,968,968,120,120,120,120,969,969,
+/* block 249 */
+986,986,986,986,986,986,986,986,986,986,986,986,986,986,986,986,
+986,986,986,986,986,986,986,986,986,986,986,986,986,986,986,986,
+986,986,987,987,987,987,987,987,987,987,987,987,987,987,987,987,
+987,987,987,987,987,987,987,987,987,987,987,987,987,987,987,987,
+987,987,987,987,988,988,988,988,988,988,988,989,120,120,120,120,
+990,990,990,990,990,990,990,990,990,990,120,120,120,120,991,991,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-/* block 243 */
+/* block 250 */
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
@@ -4158,7 +4254,7 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
-/* block 244 */
+/* block 251 */
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 20, 25, 25, 25,
@@ -4168,7 +4264,7 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-/* block 245 */
+/* block 252 */
120, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 20, 25,
@@ -4178,47 +4274,47 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-/* block 246 */
-224,224,224,224,120,224,224,224,224,224,224,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
-120,224,224,120,224,120,120,224,120,224,224,224,224,224,224,224,
-224,224,224,120,224,224,224,224,120,224,120,224,120,120,120,120,
-120,120,224,120,120,120,120,224,120,224,120,224,120,224,224,224,
-120,224,224,120,224,120,120,224,120,224,120,224,120,224,120,224,
-120,224,224,120,224,120,120,224,224,224,224,120,224,224,224,224,
-224,224,224,120,224,224,224,224,120,224,224,224,224,120,224,120,
+/* block 253 */
+225,225,225,225,120,225,225,225,225,225,225,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
+120,225,225,120,225,120,120,225,120,225,225,225,225,225,225,225,
+225,225,225,120,225,225,225,225,120,225,120,225,120,120,120,120,
+120,120,225,120,120,120,120,225,120,225,120,225,120,225,225,225,
+120,225,225,120,225,120,120,225,120,225,120,225,120,225,120,225,
+120,225,225,120,225,120,120,225,225,225,225,120,225,225,225,225,
+225,225,225,120,225,225,225,225,120,225,225,225,225,120,225,120,
-/* block 247 */
-224,224,224,224,224,224,224,224,224,224,120,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,120,120,120,120,
-120,224,224,224,120,224,224,224,224,224,120,224,224,224,224,224,
-224,224,224,224,224,224,224,224,224,224,224,224,120,120,120,120,
+/* block 254 */
+225,225,225,225,225,225,225,225,225,225,120,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,120,120,120,120,
+120,225,225,225,120,225,225,225,225,225,120,225,225,225,225,225,
+225,225,225,225,225,225,225,225,225,225,225,225,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
217,217,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-/* block 248 */
+/* block 255 */
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,970,970,970,970,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,992,992,992,992,
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, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
-/* block 249 */
+/* block 256 */
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
- 21, 21, 21, 21,970,970,970,970,970,970,970,970,970,970,970,970,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,970,
-970, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
-970, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
-970, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21,992,992,992,992,992,992,992,992,992,992,992,992,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,992,
+992, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+992, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+992, 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,970,970,970,970,970,970,970,970,970,970,
+ 21, 21, 21, 21, 21, 21,992,992,992,992,992,992,992,992,992,992,
-/* block 250 */
+/* block 257 */
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 21, 21, 21,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21,
@@ -4228,37 +4324,37 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21,
21, 21, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21,
-/* block 251 */
+/* block 258 */
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 20,
20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 20, 20, 20, 20, 20,
- 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21,970,970,
-970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
-970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
-970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
-970,970,970,970,970,970,971,971,971,971,971,971,971,971,971,971,
-971,971,971,971,971,971,971,971,971,971,971,971,971,971,971,971,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21,992,992,
+992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,
+992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,
+992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,
+992,992,992,992,992,992,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,
-/* block 252 */
-972, 21, 21,970,970,970,970,970,970,970,970,970,970,970,970,970,
+/* block 259 */
+994, 21, 21,992,992,992,992,992,992,992,992,992,992,992,992,992,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21,
- 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 20,970,970,970,970,
- 20, 20, 20, 20, 20, 20, 20, 20, 20,970,970,970,970,970,970,970,
-584,584,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
- 21, 21, 21, 21, 21, 21,970,970,970,970,970,970,970,970,970,970,
-970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
+ 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 20,992,992,992,992,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20,992,992,992,992,992,992,992,
+589,589,992,992,992,992,992,992,992,992,992,992,992,992,992,992,
+ 21, 21, 21, 21, 21, 21,992,992,992,992,992,992,992,992,992,992,
+992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,
-/* block 253 */
-970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
-970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
-970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
-970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
-970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
-970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
-970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
-970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
+/* block 260 */
+992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,
+992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,
+992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,
+992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,
+992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,
+992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,
+992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,
+992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,
-/* block 254 */
+/* block 261 */
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,
@@ -4268,7 +4364,7 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
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,
-/* block 255 */
+/* block 262 */
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,
@@ -4276,9 +4372,9 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
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,973,973,973,973,973,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,995,995,995,995,995,
-/* block 256 */
+/* block 263 */
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,
@@ -4288,7 +4384,7 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
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,
-/* block 257 */
+/* block 264 */
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,
@@ -4298,17 +4394,17 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
-/* block 258 */
+/* block 265 */
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, 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,970,970,970,970,970,970,970,970,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,970,970,970,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,970,970,970,
+ 21, 21, 21, 21, 21, 21, 21, 21,992,992,992,992,992, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,992,992,992,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,992,992,992,
-/* block 259 */
+/* block 266 */
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
@@ -4316,39 +4412,39 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
- 20, 20, 20, 20,970,970,970,970,970,970,970,970,970,970,970,970,
+ 20, 20, 20, 20,992,992,992,992,992,992,992,992,992,992,992,992,
-/* block 260 */
+/* block 267 */
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
- 20, 20, 20, 20, 20, 21, 21, 21, 21,970,970,970,970,970,970,970,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,970,970,970,970,
-970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
+ 20, 20, 20, 20, 20, 21, 21, 21, 21,992,992,992,992,992,992,992,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,992,992,992,992,
+ 21,992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,
-/* block 261 */
- 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,970,970,970,970,
+/* block 268 */
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,992,992,992,992,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
- 20, 20, 20, 20, 20, 20, 20, 20,970,970,970,970,970,970,970,970,
- 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,970,970,970,970,970,970,
+ 20, 20, 20, 20, 20, 20, 20, 20,992,992,992,992,992,992,992,992,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,992,992,992,992,992,992,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
-/* block 262 */
- 20, 20, 20, 20, 20, 20, 20, 20,970,970,970,970,970,970,970,970,
+/* block 269 */
+ 20, 20, 20, 20, 20, 20, 20, 20,992,992,992,992,992,992,992,992,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
- 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,970,970,
- 21, 21,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
-970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
-970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
-970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
-970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,992,992,
+ 21, 21,992,992,992,992,992,992,992,992,992,992,992,992,992,992,
+992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,
+992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,
+992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,
+992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,
-/* block 263 */
+/* block 270 */
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
@@ -4356,39 +4452,29 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
21, 21, 21, 21, 21, 21, 20, 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,970, 21, 21, 21, 21, 21, 21,
-
-/* block 264 */
- 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, 21, 21, 21, 21, 21,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,970, 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,
-/* block 265 */
+/* block 271 */
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, 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,970,970,970,970,970,970,970,970,970,970,970,970,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,970,970,
- 21, 21, 21, 21, 21,970,970,970, 21, 21, 21,970,970,970,970,970,
+ 21, 21, 21, 21,992,992,992,992,992,992,992,992,992,992,992,992,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,992,992,
+ 21, 21, 21, 21, 21,992,992,992, 21, 21, 21, 21, 21,992,992,992,
-/* block 266 */
- 21, 21, 21, 21, 21, 21, 21,970,970,970,970,970,970,970,970,970,
+/* block 272 */
+ 21, 21, 21, 21, 21, 21, 21,992,992,992,992,992,992,992,992,992,
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,970,970,970,970,970,970,970,
- 21, 21, 21, 21, 21, 21, 21,970,970,970,970,970,970,970,970,970,
- 21, 21, 21,970,970,970,970,970,970,970,970,970,970,970,970,970,
- 21, 21, 21, 21, 21, 21, 21,970,970,970,970,970,970,970,970,970,
-970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
-970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,992,992,992,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,992,992,992,992,992,
+ 21, 21, 21, 21, 21, 21,992,992,992,992,992,992,992,992,992,992,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,992,992,992,992,992,992,
+ 21, 21, 21, 21, 21, 21, 21, 21,992,992,992,992,992,992,992,992,
+ 21, 21, 21, 21, 21, 21, 21,992,992,992,992,992,992,992,992,992,
-/* block 267 */
+/* block 273 */
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20,120, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
@@ -4398,69 +4484,69 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11,120,120,120,120,120,120,
-/* block 268 */
-970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
-970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
-970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
-970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
-970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
-970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
-970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
-970,970,970,970,970,970,970,970,970,970,970,970,970,970,120,120,
+/* block 274 */
+992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,
+992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,
+992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,
+992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,
+992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,
+992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,
+992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,992,
+992,992,992,992,992,992,992,992,992,992,992,992,992,992,120,120,
-/* block 269 */
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,120,120,
+/* block 275 */
+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,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,591,591,591,591,
+591,591,591,591,591,591,591,591,591,591,591,591,591,591,591,591,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-/* block 270 */
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,120,120,120,120,120,120,120,120,120,120,120,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+/* block 276 */
+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,591,591,591,591,591,591,591,591,591,591,
+591,591,591,591,591,591,591,591,591,120,120,120,120,120,120,120,
+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,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,
-/* block 271 */
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,120,120,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+/* block 277 */
+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,120,120,
+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,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,591,591,591,591,
+591,591,591,591,591,591,591,591,591,591,591,591,591,591,591,591,
-/* block 272 */
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+/* block 278 */
+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,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+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,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,591,591,591,591,
-/* block 273 */
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+/* block 279 */
+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,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,591,591,591,591,
+591,591,591,591,591,591,591,591,591,591,591,591,591,591,591,591,
+591,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-/* block 274 */
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,120,120,
+/* block 280 */
+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,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
@@ -4468,37 +4554,37 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-/* block 275 */
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,586,586,586,586,120,120,120,120,120,
+/* block 281 */
+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,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,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
-/* block 276 */
-511, 24,511,511,511,511,511,511,511,511,511,511,511,511,511,511,
-511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,
-974,974,974,974,974,974,974,974,974,974,974,974,974,974,974,974,
-974,974,974,974,974,974,974,974,974,974,974,974,974,974,974,974,
-974,974,974,974,974,974,974,974,974,974,974,974,974,974,974,974,
-974,974,974,974,974,974,974,974,974,974,974,974,974,974,974,974,
-974,974,974,974,974,974,974,974,974,974,974,974,974,974,974,974,
-974,974,974,974,974,974,974,974,974,974,974,974,974,974,974,974,
+/* block 282 */
+516, 24,516,516,516,516,516,516,516,516,516,516,516,516,516,516,
+516,516,516,516,516,516,516,516,516,516,516,516,516,516,516,516,
+996,996,996,996,996,996,996,996,996,996,996,996,996,996,996,996,
+996,996,996,996,996,996,996,996,996,996,996,996,996,996,996,996,
+996,996,996,996,996,996,996,996,996,996,996,996,996,996,996,996,
+996,996,996,996,996,996,996,996,996,996,996,996,996,996,996,996,
+996,996,996,996,996,996,996,996,996,996,996,996,996,996,996,996,
+996,996,996,996,996,996,996,996,996,996,996,996,996,996,996,996,
-/* block 277 */
-511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,
-511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,
-511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,
-511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,
-511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,
-511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,
-511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,
-511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,
+/* block 283 */
+516,516,516,516,516,516,516,516,516,516,516,516,516,516,516,516,
+516,516,516,516,516,516,516,516,516,516,516,516,516,516,516,516,
+516,516,516,516,516,516,516,516,516,516,516,516,516,516,516,516,
+516,516,516,516,516,516,516,516,516,516,516,516,516,516,516,516,
+516,516,516,516,516,516,516,516,516,516,516,516,516,516,516,516,
+516,516,516,516,516,516,516,516,516,516,516,516,516,516,516,516,
+516,516,516,516,516,516,516,516,516,516,516,516,516,516,516,516,
+516,516,516,516,516,516,516,516,516,516,516,516,516,516,516,516,
-/* block 278 */
+/* block 284 */
113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
@@ -4508,7 +4594,7 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
-/* block 279 */
+/* block 285 */
113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
@@ -4516,17 +4602,17 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
-511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,
-
-/* block 280 */
-673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
-673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
-673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
-673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
-673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
-673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
-673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
-673,673,673,673,673,673,673,673,673,673,673,673,673,673,120,120,
+516,516,516,516,516,516,516,516,516,516,516,516,516,516,516,516,
+
+/* block 286 */
+678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,
+678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,
+678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,
+678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,
+678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,
+678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,
+678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,
+678,678,678,678,678,678,678,678,678,678,678,678,678,678,120,120,
};
diff --git a/thirdparty/pcre2/src/pcre2_ucp.h b/thirdparty/pcre2/src/pcre2_ucp.h
index 9538062c71..d84f269e87 100644
--- a/thirdparty/pcre2/src/pcre2_ucp.h
+++ b/thirdparty/pcre2/src/pcre2_ucp.h
@@ -291,7 +291,13 @@ enum {
ucp_Chorasmian,
ucp_Dives_Akuru,
ucp_Khitan_Small_Script,
- ucp_Yezidi
+ ucp_Yezidi,
+ /* New for Unicode 14.0.0 */
+ ucp_Cypro_Minoan,
+ ucp_Old_Uyghur,
+ ucp_Tangsa,
+ ucp_Toto,
+ ucp_Vithkuqi
};
#endif /* PCRE2_UCP_H_IDEMPOTENT_GUARD */
diff --git a/thirdparty/pcre2/src/sljit/sljitConfigInternal.h b/thirdparty/pcre2/src/sljit/sljitConfigInternal.h
index eb1132db30..7bb9990a59 100644
--- a/thirdparty/pcre2/src/sljit/sljitConfigInternal.h
+++ b/thirdparty/pcre2/src/sljit/sljitConfigInternal.h
@@ -158,6 +158,8 @@ extern "C" {
#define SLJIT_CONFIG_MIPS_64 1
#elif defined(__sparc__) || defined(__sparc)
#define SLJIT_CONFIG_SPARC_32 1
+#elif defined(__s390x__)
+#define SLJIT_CONFIG_S390X 1
#else
/* Unsupported architecture */
#define SLJIT_CONFIG_UNSUPPORTED 1
@@ -759,6 +761,18 @@ 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)
+/********************************/
+/* CPU status flags management. */
+/********************************/
+
+#if (defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) \
+ || (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
+ || (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS) \
+ || (defined SLJIT_CONFIG_SPARC && SLJIT_CONFIG_SPARC) \
+ || (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X)
+#define SLJIT_HAS_STATUS_FLAGS_STATE 1
+#endif
+
/*************************************/
/* Debug and verbose related macros. */
/*************************************/
diff --git a/thirdparty/pcre2/src/sljit/sljitExecAllocator.c b/thirdparty/pcre2/src/sljit/sljitExecAllocator.c
index 61a32f23e9..6e5bf78e45 100644
--- a/thirdparty/pcre2/src/sljit/sljitExecAllocator.c
+++ b/thirdparty/pcre2/src/sljit/sljitExecAllocator.c
@@ -79,6 +79,7 @@
*/
#ifdef _WIN32
+#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec)
static SLJIT_INLINE void* alloc_chunk(sljit_uw size)
{
@@ -91,96 +92,108 @@ static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
VirtualFree(chunk, 0, MEM_RELEASE);
}
-#else
-
-#ifdef __APPLE__
-#ifdef MAP_ANON
-/* Configures TARGET_OS_OSX when appropriate */
-#include <TargetConditionals.h>
-
-#if TARGET_OS_OSX && defined(MAP_JIT)
-#include <sys/utsname.h>
-#endif /* TARGET_OS_OSX && MAP_JIT */
-
-#ifdef MAP_JIT
+#else /* POSIX */
+#if defined(__APPLE__) && defined(MAP_JIT)
/*
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.
+ 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 TARGET_OS_OSX
+#if defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86
+#ifdef MAP_ANON
+#include <sys/utsname.h>
+#include <stdlib.h>
+
+#define SLJIT_MAP_JIT (get_map_jit_flag())
+
static SLJIT_INLINE int get_map_jit_flag()
{
-#if TARGET_OS_OSX
- sljit_sw page_size = get_page_alignment() + 1;
+ sljit_sw page_size;
void *ptr;
+ struct utsname name;
static int map_jit_flag = -1;
- /*
- The following code is thread safe because multiple initialization
- sets map_jit_flag to the same value and the code has no side-effects.
- Changing the kernel version witout system restart is (very) unlikely.
- */
- if (map_jit_flag == -1) {
- struct utsname name;
-
+ if (map_jit_flag < 0) {
map_jit_flag = 0;
uname(&name);
- /* Kernel version for 10.14.0 (Mojave) */
+ /* 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);
- ptr = mmap(NULL, page_size, PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0);
-
- if (ptr == MAP_FAILED) {
- map_jit_flag = MAP_JIT;
- } else {
+ if (ptr != MAP_FAILED)
munmap(ptr, page_size);
- }
+ else
+ map_jit_flag = MAP_JIT;
}
}
-
return map_jit_flag;
-#else /* !TARGET_OS_OSX */
- return MAP_JIT;
-#endif /* TARGET_OS_OSX */
}
-
-#endif /* MAP_JIT */
#endif /* MAP_ANON */
-#endif /* __APPLE__ */
+#else /* !SLJIT_CONFIG_X86 */
+#if !(defined SLJIT_CONFIG_ARM && SLJIT_CONFIG_ARM)
+#error Unsupported architecture
+#endif /* SLJIT_CONFIG_ARM */
+#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)
+{
+ pthread_jit_write_protect_np(enable_exec);
+}
+#endif /* SLJIT_CONFIG_X86 */
+#else /* !TARGET_OS_OSX */
+#define SLJIT_MAP_JIT (MAP_JIT)
+#endif /* TARGET_OS_OSX */
+#endif /* __APPLE__ && MAP_JIT */
+#ifndef SLJIT_UPDATE_WX_FLAGS
+#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec)
+#endif /* !SLJIT_UPDATE_WX_FLAGS */
+#ifndef SLJIT_MAP_JIT
+#define SLJIT_MAP_JIT (0)
+#endif /* !SLJIT_MAP_JIT */
static SLJIT_INLINE void* alloc_chunk(sljit_uw size)
{
void *retval;
- const int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
-
-#ifdef MAP_ANON
+ int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
+ int flags = MAP_PRIVATE;
+ int fd = -1;
- int flags = MAP_PRIVATE | MAP_ANON;
-
-#ifdef MAP_JIT
- flags |= get_map_jit_flag();
+#ifdef PROT_MAX
+ prot |= PROT_MAX(prot);
#endif
- retval = mmap(NULL, size, prot, flags, -1, 0);
+#ifdef MAP_ANON
+ flags |= MAP_ANON | SLJIT_MAP_JIT;
#else /* !MAP_ANON */
if (SLJIT_UNLIKELY((dev_zero < 0) && open_dev_zero()))
return NULL;
- retval = mmap(NULL, size, prot, MAP_PRIVATE, dev_zero, 0);
+ fd = dev_zero;
#endif /* MAP_ANON */
+ retval = mmap(NULL, size, prot, flags, fd, 0);
if (retval == MAP_FAILED)
- retval = NULL;
- else {
- if (mprotect(retval, size, prot) < 0) {
- munmap(retval, size);
- retval = NULL;
- }
+ return NULL;
+
+ if (mprotect(retval, size, PROT_READ | PROT_WRITE | PROT_EXEC) < 0) {
+ munmap(retval, size);
+ return NULL;
}
+ SLJIT_UPDATE_WX_FLAGS(retval, (uint8_t *)retval + size, 0);
+
return retval;
}
@@ -189,7 +202,7 @@ static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
munmap(chunk, size);
}
-#endif
+#endif /* windows */
/* --------------------------------------------------------------------- */
/* Common functions */
@@ -261,6 +274,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
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;
@@ -326,6 +340,7 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr)
allocated_size -= header->size;
/* Connecting free blocks together if possible. */
+ SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 0);
/* If header->prev_size == 0, free_block will equal to header.
In this case, free_block->header.size will be > 0. */
@@ -358,6 +373,7 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr)
}
}
+ SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 1);
SLJIT_ALLOCATOR_UNLOCK();
}
@@ -367,6 +383,7 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void)
struct free_block* next_free_block;
SLJIT_ALLOCATOR_LOCK();
+ SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 0);
free_block = free_blocks;
while (free_block) {
@@ -381,5 +398,6 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void)
}
SLJIT_ASSERT((total_size && free_blocks) || (!total_size && !free_blocks));
+ SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 1);
SLJIT_ALLOCATOR_UNLOCK();
}
diff --git a/thirdparty/pcre2/src/sljit/sljitLir.c b/thirdparty/pcre2/src/sljit/sljitLir.c
index d817c90b3a..a24a99ab87 100644
--- a/thirdparty/pcre2/src/sljit/sljitLir.c
+++ b/thirdparty/pcre2/src/sljit/sljitLir.c
@@ -532,13 +532,21 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_put_label(struct sljit_put_label *put_la
put_label->label = label;
}
+#define SLJIT_CURRENT_FLAGS_ALL \
+ (SLJIT_CURRENT_FLAGS_I32_OP | SLJIT_CURRENT_FLAGS_ADD_SUB | SLJIT_CURRENT_FLAGS_COMPARE)
+
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);
+#if (defined SLJIT_HAS_STATUS_FLAGS_STATE && SLJIT_HAS_STATUS_FLAGS_STATE)
+ compiler->status_flags_state = current_flags;
+#endif
+
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
- if ((current_flags & ~(VARIABLE_FLAG_MASK | SLJIT_I32_OP | SLJIT_SET_Z)) == 0) {
+ compiler->last_flags = 0;
+ if ((current_flags & ~(VARIABLE_FLAG_MASK | SLJIT_SET_Z | SLJIT_CURRENT_FLAGS_ALL)) == 0) {
compiler->last_flags = GET_FLAG_TYPE(current_flags) | (current_flags & (SLJIT_I32_OP | SLJIT_SET_Z));
}
#endif
@@ -968,7 +976,7 @@ static const char* fop2_names[] = {
};
#define JUMP_POSTFIX(type) \
- ((type & 0xff) <= SLJIT_MUL_NOT_OVERFLOW ? ((type & SLJIT_I32_OP) ? "32" : "") \
+ ((type & 0xff) <= SLJIT_NOT_OVERFLOW ? ((type & SLJIT_I32_OP) ? "32" : "") \
: ((type & 0xff) <= SLJIT_ORDERED_F64 ? ((type & SLJIT_F32_OP) ? ".f32" : ".f64") : ""))
static char* jump_names[] = {
@@ -978,7 +986,6 @@ static char* jump_names[] = {
(char*)"sig_less", (char*)"sig_greater_equal",
(char*)"sig_greater", (char*)"sig_less_equal",
(char*)"overflow", (char*)"not_overflow",
- (char*)"mul_overflow", (char*)"mul_not_overflow",
(char*)"carry", (char*)"",
(char*)"equal", (char*)"not_equal",
(char*)"less", (char*)"greater_equal",
@@ -1278,7 +1285,7 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op2(struct sljit_compiler
case SLJIT_MUL:
CHECK_ARGUMENT(!(op & SLJIT_SET_Z));
CHECK_ARGUMENT(!(op & VARIABLE_FLAG_MASK)
- || GET_FLAG_TYPE(op) == SLJIT_MUL_OVERFLOW);
+ || GET_FLAG_TYPE(op) == SLJIT_OVERFLOW);
break;
case SLJIT_ADD:
CHECK_ARGUMENT(!(op & VARIABLE_FLAG_MASK)
@@ -1601,9 +1608,7 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_jump(struct sljit_compile
CHECK_ARGUMENT(compiler->last_flags & SLJIT_SET_Z);
else
CHECK_ARGUMENT((type & 0xff) == (compiler->last_flags & 0xff)
- || ((type & 0xff) == SLJIT_NOT_OVERFLOW && (compiler->last_flags & 0xff) == SLJIT_OVERFLOW)
- || ((type & 0xff) == SLJIT_MUL_NOT_OVERFLOW && (compiler->last_flags & 0xff) == SLJIT_MUL_OVERFLOW));
- CHECK_ARGUMENT((type & SLJIT_I32_OP) == (compiler->last_flags & SLJIT_I32_OP));
+ || ((type & 0xff) == SLJIT_NOT_OVERFLOW && (compiler->last_flags & 0xff) == SLJIT_OVERFLOW));
}
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
@@ -1818,8 +1823,7 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op_flags(struct sljit_com
CHECK_ARGUMENT(compiler->last_flags & SLJIT_SET_Z);
else
CHECK_ARGUMENT((type & 0xff) == (compiler->last_flags & 0xff)
- || ((type & 0xff) == SLJIT_NOT_OVERFLOW && (compiler->last_flags & 0xff) == SLJIT_OVERFLOW)
- || ((type & 0xff) == SLJIT_MUL_NOT_OVERFLOW && (compiler->last_flags & 0xff) == SLJIT_MUL_OVERFLOW));
+ || ((type & 0xff) == SLJIT_NOT_OVERFLOW && (compiler->last_flags & 0xff) == SLJIT_OVERFLOW));
FUNCTION_CHECK_DST(dst, dstw, 0);
@@ -1858,8 +1862,7 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_cmov(struct sljit_compile
CHECK_ARGUMENT(compiler->last_flags & SLJIT_SET_Z);
else
CHECK_ARGUMENT((type & 0xff) == (compiler->last_flags & 0xff)
- || ((type & 0xff) == SLJIT_NOT_OVERFLOW && (compiler->last_flags & 0xff) == SLJIT_OVERFLOW)
- || ((type & 0xff) == SLJIT_MUL_NOT_OVERFLOW && (compiler->last_flags & 0xff) == SLJIT_MUL_OVERFLOW));
+ || ((type & 0xff) == SLJIT_NOT_OVERFLOW && (compiler->last_flags & 0xff) == SLJIT_OVERFLOW));
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
diff --git a/thirdparty/pcre2/src/sljit/sljitLir.h b/thirdparty/pcre2/src/sljit/sljitLir.h
index 93d2804675..0eb62fc21b 100644
--- a/thirdparty/pcre2/src/sljit/sljitLir.h
+++ b/thirdparty/pcre2/src/sljit/sljitLir.h
@@ -412,6 +412,10 @@ struct sljit_compiler {
/* Executable size for statistical purposes. */
sljit_uw executable_size;
+#if (defined SLJIT_HAS_STATUS_FLAGS_STATE && SLJIT_HAS_STATUS_FLAGS_STATE)
+ sljit_s32 status_flags_state;
+#endif
+
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
sljit_s32 args;
sljit_s32 locals_offset;
@@ -460,7 +464,7 @@ struct sljit_compiler {
#if (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X)
/* Need to allocate register save area to make calls. */
- sljit_s32 have_save_area;
+ sljit_s32 mode;
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
@@ -996,7 +1000,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
#define SLJIT_SUBC (SLJIT_OP2_BASE + 3)
#define SLJIT_SUBC32 (SLJIT_SUBC | SLJIT_I32_OP)
/* Note: integer mul
- Flags: MUL_OVERFLOW */
+ Flags: OVERFLOW */
#define SLJIT_MUL (SLJIT_OP2_BASE + 4)
#define SLJIT_MUL32 (SLJIT_MUL | SLJIT_I32_OP)
/* Flags: Z */
@@ -1141,89 +1145,69 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compi
/* Integer comparison types. */
#define SLJIT_EQUAL 0
-#define SLJIT_EQUAL32 (SLJIT_EQUAL | SLJIT_I32_OP)
-#define SLJIT_ZERO 0
-#define SLJIT_ZERO32 (SLJIT_ZERO | SLJIT_I32_OP)
+#define SLJIT_ZERO SLJIT_EQUAL
#define SLJIT_NOT_EQUAL 1
-#define SLJIT_NOT_EQUAL32 (SLJIT_NOT_EQUAL | SLJIT_I32_OP)
-#define SLJIT_NOT_ZERO 1
-#define SLJIT_NOT_ZERO32 (SLJIT_NOT_ZERO | SLJIT_I32_OP)
+#define SLJIT_NOT_ZERO SLJIT_NOT_EQUAL
#define SLJIT_LESS 2
-#define SLJIT_LESS32 (SLJIT_LESS | SLJIT_I32_OP)
#define SLJIT_SET_LESS SLJIT_SET(SLJIT_LESS)
#define SLJIT_GREATER_EQUAL 3
-#define SLJIT_GREATER_EQUAL32 (SLJIT_GREATER_EQUAL | SLJIT_I32_OP)
#define SLJIT_SET_GREATER_EQUAL SLJIT_SET(SLJIT_GREATER_EQUAL)
#define SLJIT_GREATER 4
-#define SLJIT_GREATER32 (SLJIT_GREATER | SLJIT_I32_OP)
#define SLJIT_SET_GREATER SLJIT_SET(SLJIT_GREATER)
#define SLJIT_LESS_EQUAL 5
-#define SLJIT_LESS_EQUAL32 (SLJIT_LESS_EQUAL | SLJIT_I32_OP)
#define SLJIT_SET_LESS_EQUAL SLJIT_SET(SLJIT_LESS_EQUAL)
#define SLJIT_SIG_LESS 6
-#define SLJIT_SIG_LESS32 (SLJIT_SIG_LESS | SLJIT_I32_OP)
#define SLJIT_SET_SIG_LESS SLJIT_SET(SLJIT_SIG_LESS)
#define SLJIT_SIG_GREATER_EQUAL 7
-#define SLJIT_SIG_GREATER_EQUAL32 (SLJIT_SIG_GREATER_EQUAL | SLJIT_I32_OP)
#define SLJIT_SET_SIG_GREATER_EQUAL SLJIT_SET(SLJIT_SIG_GREATER_EQUAL)
#define SLJIT_SIG_GREATER 8
-#define SLJIT_SIG_GREATER32 (SLJIT_SIG_GREATER | SLJIT_I32_OP)
#define SLJIT_SET_SIG_GREATER SLJIT_SET(SLJIT_SIG_GREATER)
#define SLJIT_SIG_LESS_EQUAL 9
-#define SLJIT_SIG_LESS_EQUAL32 (SLJIT_SIG_LESS_EQUAL | SLJIT_I32_OP)
#define SLJIT_SET_SIG_LESS_EQUAL SLJIT_SET(SLJIT_SIG_LESS_EQUAL)
#define SLJIT_OVERFLOW 10
-#define SLJIT_OVERFLOW32 (SLJIT_OVERFLOW | SLJIT_I32_OP)
#define SLJIT_SET_OVERFLOW SLJIT_SET(SLJIT_OVERFLOW)
#define SLJIT_NOT_OVERFLOW 11
-#define SLJIT_NOT_OVERFLOW32 (SLJIT_NOT_OVERFLOW | SLJIT_I32_OP)
-
-#define SLJIT_MUL_OVERFLOW 12
-#define SLJIT_MUL_OVERFLOW32 (SLJIT_MUL_OVERFLOW | SLJIT_I32_OP)
-#define SLJIT_SET_MUL_OVERFLOW SLJIT_SET(SLJIT_MUL_OVERFLOW)
-#define SLJIT_MUL_NOT_OVERFLOW 13
-#define SLJIT_MUL_NOT_OVERFLOW32 (SLJIT_MUL_NOT_OVERFLOW | SLJIT_I32_OP)
/* There is no SLJIT_CARRY or SLJIT_NOT_CARRY. */
-#define SLJIT_SET_CARRY SLJIT_SET(14)
+#define SLJIT_SET_CARRY SLJIT_SET(12)
/* Floating point comparison types. */
-#define SLJIT_EQUAL_F64 16
+#define SLJIT_EQUAL_F64 14
#define SLJIT_EQUAL_F32 (SLJIT_EQUAL_F64 | SLJIT_F32_OP)
#define SLJIT_SET_EQUAL_F SLJIT_SET(SLJIT_EQUAL_F64)
-#define SLJIT_NOT_EQUAL_F64 17
+#define SLJIT_NOT_EQUAL_F64 15
#define SLJIT_NOT_EQUAL_F32 (SLJIT_NOT_EQUAL_F64 | SLJIT_F32_OP)
#define SLJIT_SET_NOT_EQUAL_F SLJIT_SET(SLJIT_NOT_EQUAL_F64)
-#define SLJIT_LESS_F64 18
+#define SLJIT_LESS_F64 16
#define SLJIT_LESS_F32 (SLJIT_LESS_F64 | SLJIT_F32_OP)
#define SLJIT_SET_LESS_F SLJIT_SET(SLJIT_LESS_F64)
-#define SLJIT_GREATER_EQUAL_F64 19
+#define SLJIT_GREATER_EQUAL_F64 17
#define SLJIT_GREATER_EQUAL_F32 (SLJIT_GREATER_EQUAL_F64 | SLJIT_F32_OP)
#define SLJIT_SET_GREATER_EQUAL_F SLJIT_SET(SLJIT_GREATER_EQUAL_F64)
-#define SLJIT_GREATER_F64 20
+#define SLJIT_GREATER_F64 18
#define SLJIT_GREATER_F32 (SLJIT_GREATER_F64 | SLJIT_F32_OP)
#define SLJIT_SET_GREATER_F SLJIT_SET(SLJIT_GREATER_F64)
-#define SLJIT_LESS_EQUAL_F64 21
+#define SLJIT_LESS_EQUAL_F64 19
#define SLJIT_LESS_EQUAL_F32 (SLJIT_LESS_EQUAL_F64 | SLJIT_F32_OP)
#define SLJIT_SET_LESS_EQUAL_F SLJIT_SET(SLJIT_LESS_EQUAL_F64)
-#define SLJIT_UNORDERED_F64 22
+#define SLJIT_UNORDERED_F64 20
#define SLJIT_UNORDERED_F32 (SLJIT_UNORDERED_F64 | SLJIT_F32_OP)
#define SLJIT_SET_UNORDERED_F SLJIT_SET(SLJIT_UNORDERED_F64)
-#define SLJIT_ORDERED_F64 23
+#define SLJIT_ORDERED_F64 21
#define SLJIT_ORDERED_F32 (SLJIT_ORDERED_F64 | SLJIT_F32_OP)
#define SLJIT_SET_ORDERED_F SLJIT_SET(SLJIT_ORDERED_F64)
/* Unconditional jump types. */
-#define SLJIT_JUMP 24
+#define SLJIT_JUMP 22
/* Fast calling method. See sljit_emit_fast_enter / SLJIT_FAST_RETURN. */
-#define SLJIT_FAST_CALL 25
+#define SLJIT_FAST_CALL 23
/* Called function must be declared with the SLJIT_FUNC attribute. */
-#define SLJIT_CALL 26
+#define SLJIT_CALL 24
/* Called function must be declared with cdecl attribute.
This is the default attribute for C functions. */
-#define SLJIT_CALL_CDECL 27
+#define SLJIT_CALL_CDECL 25
/* The target can be changed during runtime (see: sljit_set_jump_addr). */
#define SLJIT_REWRITABLE_JUMP 0x1000
@@ -1534,8 +1518,22 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg)
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
void *instruction, sljit_s32 size);
-/* Define the currently available CPU status flags. It is usually used after an
- sljit_emit_op_custom call to define which flags are set. */
+/* Flags were set by a 32 bit operation. */
+#define SLJIT_CURRENT_FLAGS_I32_OP SLJIT_I32_OP
+
+/* Flags were set by an ADD, ADDC, SUB, SUBC, or NEG operation. */
+#define SLJIT_CURRENT_FLAGS_ADD_SUB 0x01
+
+/* Flags were set by a SUB with unused destination.
+ Must be combined with SLJIT_CURRENT_FLAGS_ADD_SUB. */
+#define SLJIT_CURRENT_FLAGS_COMPARE 0x02
+
+/* Define the currently available CPU status flags. It is usually used after
+ an sljit_emit_label or sljit_emit_op_custom operations to define which CPU
+ status flags are available.
+
+ The current_flags must be a valid combination of SLJIT_SET_* and
+ SLJIT_CURRENT_FLAGS_* constants. */
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_current_flags(struct sljit_compiler *compiler,
sljit_s32 current_flags);
diff --git a/thirdparty/pcre2/src/sljit/sljitNativeARM_32.c b/thirdparty/pcre2/src/sljit/sljitNativeARM_32.c
index ae8479f031..74cf55fcd2 100644
--- a/thirdparty/pcre2/src/sljit/sljitNativeARM_32.c
+++ b/thirdparty/pcre2/src/sljit/sljitNativeARM_32.c
@@ -1197,6 +1197,8 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
case SLJIT_ADD:
SLJIT_ASSERT(!(flags & INV_IMM));
+ compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD_SUB;
+
if ((flags & (UNUSED_RETURN | SET_FLAGS)) == (UNUSED_RETURN | SET_FLAGS) && !(flags & ARGS_SWAPPED))
return push_inst(compiler, CMN | SET_FLAGS | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2)));
return push_inst(compiler, ADD | (flags & SET_FLAGS) | RD(dst) | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2)));
@@ -1207,6 +1209,8 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
case SLJIT_SUB:
SLJIT_ASSERT(!(flags & INV_IMM));
+ compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD_SUB;
+
if ((flags & (UNUSED_RETURN | SET_FLAGS)) == (UNUSED_RETURN | SET_FLAGS) && !(flags & ARGS_SWAPPED))
return push_inst(compiler, CMP | SET_FLAGS | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2)));
return push_inst(compiler, (!(flags & ARGS_SWAPPED) ? SUB : RSB) | (flags & SET_FLAGS)
@@ -1220,6 +1224,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
case SLJIT_MUL:
SLJIT_ASSERT(!(flags & INV_IMM));
SLJIT_ASSERT(!(src2 & SRC2_IMM));
+ compiler->status_flags_state = 0;
if (!HAS_FLAGS(op))
return push_inst(compiler, MUL | (reg_map[dst] << 16) | (reg_map[src2] << 8) | reg_map[src1]);
@@ -2153,16 +2158,14 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *
/* Conditional instructions */
/* --------------------------------------------------------------------- */
-static sljit_uw get_cc(sljit_s32 type)
+static sljit_uw get_cc(struct sljit_compiler *compiler, sljit_s32 type)
{
switch (type) {
case SLJIT_EQUAL:
- case SLJIT_MUL_NOT_OVERFLOW:
case SLJIT_EQUAL_F64:
return 0x00000000;
case SLJIT_NOT_EQUAL:
- case SLJIT_MUL_OVERFLOW:
case SLJIT_NOT_EQUAL_F64:
return 0x10000000;
@@ -2195,10 +2198,16 @@ static sljit_uw get_cc(sljit_s32 type)
return 0xd0000000;
case SLJIT_OVERFLOW:
+ if (!(compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD_SUB))
+ return 0x10000000;
+
case SLJIT_UNORDERED_F64:
return 0x60000000;
case SLJIT_NOT_OVERFLOW:
+ if (!(compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD_SUB))
+ return 0x00000000;
+
case SLJIT_ORDERED_F64:
return 0x70000000;
@@ -2242,7 +2251,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
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,
- type <= SLJIT_JUMP ? TMP_PC : TMP_REG1, TMP_PC, 0)) & ~COND_MASK) | get_cc(type), 0));
+ type <= SLJIT_JUMP ? TMP_PC : TMP_REG1, TMP_PC, 0)) & ~COND_MASK) | get_cc(compiler, type), 0));
if (jump->flags & SLJIT_REWRITABLE_JUMP) {
jump->addr = compiler->size;
@@ -2260,7 +2269,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
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(type)));
+ 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
return jump;
@@ -2589,7 +2598,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
ADJUST_LOCAL_OFFSET(dst, dstw);
op = GET_OPCODE(op);
- cc = get_cc(type & 0xff);
+ cc = get_cc(compiler, type & 0xff);
dst_reg = FAST_IS_REG(dst) ? dst : TMP_REG1;
if (op < SLJIT_ADD) {
@@ -2629,7 +2638,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compil
dst_reg &= ~SLJIT_I32_OP;
- cc = get_cc(type & 0xff);
+ cc = get_cc(compiler, type & 0xff);
if (SLJIT_UNLIKELY(src & SLJIT_IMM)) {
tmp = get_imm(srcw);
diff --git a/thirdparty/pcre2/src/sljit/sljitNativeARM_64.c b/thirdparty/pcre2/src/sljit/sljitNativeARM_64.c
index 52267e7df7..3f0f5fcc30 100644
--- a/thirdparty/pcre2/src/sljit/sljitNativeARM_64.c
+++ b/thirdparty/pcre2/src/sljit/sljitNativeARM_64.c
@@ -644,6 +644,7 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
imm = -imm;
/* Fall through. */
case SLJIT_ADD:
+ compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD_SUB;
if (imm == 0) {
CHECK_FLAGS(1 << 29);
return push_inst(compiler, ((op == SLJIT_ADD ? ADDI : SUBI) ^ inv_bits) | RD(dst) | RN(reg));
@@ -781,6 +782,7 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
break; /* Set flags. */
case SLJIT_NEG:
SLJIT_ASSERT(arg1 == TMP_REG1);
+ compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD_SUB;
if (flags & SET_FLAGS)
inv_bits |= 1 << 29;
return push_inst(compiler, (SUB ^ inv_bits) | RD(dst) | RN(TMP_ZERO) | RM(arg2));
@@ -789,17 +791,20 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
return push_inst(compiler, (CLZ ^ inv_bits) | RD(dst) | RN(arg2));
case SLJIT_ADD:
CHECK_FLAGS(1 << 29);
+ compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD_SUB;
return push_inst(compiler, (ADD ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2));
case SLJIT_ADDC:
CHECK_FLAGS(1 << 29);
return push_inst(compiler, (ADC ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2));
case SLJIT_SUB:
CHECK_FLAGS(1 << 29);
+ compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD_SUB;
return push_inst(compiler, (SUB ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2));
case SLJIT_SUBC:
CHECK_FLAGS(1 << 29);
return push_inst(compiler, (SBC ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2));
case SLJIT_MUL:
+ compiler->status_flags_state = 0;
if (!(flags & SET_FLAGS))
return push_inst(compiler, (MADD ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2) | RT2(TMP_ZERO));
if (flags & INT_OP) {
@@ -1600,16 +1605,14 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *
/* Conditional instructions */
/* --------------------------------------------------------------------- */
-static sljit_uw get_cc(sljit_s32 type)
+static sljit_uw get_cc(struct sljit_compiler *compiler, sljit_s32 type)
{
switch (type) {
case SLJIT_EQUAL:
- case SLJIT_MUL_NOT_OVERFLOW:
case SLJIT_EQUAL_F64:
return 0x1;
case SLJIT_NOT_EQUAL:
- case SLJIT_MUL_OVERFLOW:
case SLJIT_NOT_EQUAL_F64:
return 0x0;
@@ -1642,10 +1645,16 @@ static sljit_uw get_cc(sljit_s32 type)
return 0xc;
case SLJIT_OVERFLOW:
+ if (!(compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD_SUB))
+ return 0x0;
+
case SLJIT_UNORDERED_F64:
return 0x7;
case SLJIT_NOT_OVERFLOW:
+ if (!(compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD_SUB))
+ return 0x1;
+
case SLJIT_ORDERED_F64:
return 0x6;
@@ -1685,7 +1694,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
if (type < SLJIT_JUMP) {
jump->flags |= IS_COND;
- PTR_FAIL_IF(push_inst(compiler, B_CC | (6 << 5) | get_cc(type)));
+ PTR_FAIL_IF(push_inst(compiler, B_CC | (6 << 5) | get_cc(compiler, type)));
}
else if (type >= SLJIT_FAST_CALL)
jump->flags |= IS_BL;
@@ -1799,7 +1808,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, type));
ADJUST_LOCAL_OFFSET(dst, dstw);
- cc = get_cc(type & 0xff);
+ cc = get_cc(compiler, type & 0xff);
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
if (GET_OPCODE(op) < SLJIT_ADD) {
@@ -1854,7 +1863,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compil
srcw = 0;
}
- cc = get_cc(type & 0xff);
+ cc = get_cc(compiler, type & 0xff);
dst_reg &= ~SLJIT_I32_OP;
return push_inst(compiler, (CSEL ^ inv_bits) | (cc << 12) | RD(dst_reg) | RN(dst_reg) | RM(src));
diff --git a/thirdparty/pcre2/src/sljit/sljitNativeARM_T2_32.c b/thirdparty/pcre2/src/sljit/sljitNativeARM_T2_32.c
index 4624882f42..e35dbe99b3 100644
--- a/thirdparty/pcre2/src/sljit/sljitNativeARM_T2_32.c
+++ b/thirdparty/pcre2/src/sljit/sljitNativeARM_T2_32.c
@@ -610,6 +610,7 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
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_SUB;
nimm = -(sljit_sw)imm;
if (IS_2_LO_REGS(reg, dst)) {
if (imm <= 0x7)
@@ -643,6 +644,7 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
break;
case SLJIT_SUB:
/* SUB operation can be replaced by ADD because of the negative carry flag. */
+ compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD_SUB;
if (flags & ARG1_IMM) {
if (imm == 0 && IS_2_LO_REGS(reg, dst))
return push_inst16(compiler, RSBSI | RD3(dst) | RN3(reg));
@@ -801,6 +803,7 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
FAIL_IF(push_inst32(compiler, CLZ | RN4(arg2) | RD4(dst) | RM4(arg2)));
return SLJIT_SUCCESS;
case SLJIT_ADD:
+ compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD_SUB;
if (IS_3_LO_REGS(dst, arg1, arg2))
return push_inst16(compiler, ADDS | RD3(dst) | RN3(arg1) | RM3(arg2));
if (dst == arg1 && !(flags & SET_FLAGS))
@@ -811,6 +814,7 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
return push_inst16(compiler, ADCS | RD3(dst) | RN3(arg2));
return push_inst32(compiler, ADC_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2));
case SLJIT_SUB:
+ compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD_SUB;
if (flags & UNUSED_RETURN) {
if (IS_2_LO_REGS(arg1, arg2))
return push_inst16(compiler, CMP | RD3(arg1) | RN3(arg2));
@@ -824,6 +828,7 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
return push_inst16(compiler, SBCS | RD3(dst) | RN3(arg2));
return push_inst32(compiler, SBC_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2));
case SLJIT_MUL:
+ compiler->status_flags_state = 0;
if (!(flags & SET_FLAGS))
return push_inst32(compiler, MUL | RD4(dst) | RN4(arg1) | RM4(arg2));
SLJIT_ASSERT(dst != TMP_REG2);
@@ -1760,16 +1765,14 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *
/* Conditional instructions */
/* --------------------------------------------------------------------- */
-static sljit_uw get_cc(sljit_s32 type)
+static sljit_uw get_cc(struct sljit_compiler *compiler, sljit_s32 type)
{
switch (type) {
case SLJIT_EQUAL:
- case SLJIT_MUL_NOT_OVERFLOW:
case SLJIT_EQUAL_F64:
return 0x0;
case SLJIT_NOT_EQUAL:
- case SLJIT_MUL_OVERFLOW:
case SLJIT_NOT_EQUAL_F64:
return 0x1;
@@ -1802,10 +1805,16 @@ static sljit_uw get_cc(sljit_s32 type)
return 0xd;
case SLJIT_OVERFLOW:
+ if (!(compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD_SUB))
+ return 0x1;
+
case SLJIT_UNORDERED_F64:
return 0x6;
case SLJIT_NOT_OVERFLOW:
+ if (!(compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD_SUB))
+ return 0x0;
+
case SLJIT_ORDERED_F64:
return 0x7;
@@ -1847,7 +1856,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
PTR_FAIL_IF(emit_imm32_const(compiler, TMP_REG1, 0));
if (type < SLJIT_JUMP) {
jump->flags |= IS_COND;
- cc = get_cc(type);
+ cc = get_cc(compiler, type);
jump->flags |= cc << 8;
PTR_FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8));
}
@@ -2177,7 +2186,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
ADJUST_LOCAL_OFFSET(dst, dstw);
op = GET_OPCODE(op);
- cc = get_cc(type & 0xff);
+ cc = get_cc(compiler, type & 0xff);
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
if (op < SLJIT_ADD) {
@@ -2229,7 +2238,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compil
dst_reg &= ~SLJIT_I32_OP;
- cc = get_cc(type & 0xff);
+ cc = get_cc(compiler, type & 0xff);
if (!(src & SLJIT_IMM)) {
FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8));
diff --git a/thirdparty/pcre2/src/sljit/sljitNativeMIPS_32.c b/thirdparty/pcre2/src/sljit/sljitNativeMIPS_32.c
index f887ee1311..a90345f1f8 100644
--- a/thirdparty/pcre2/src/sljit/sljitNativeMIPS_32.c
+++ b/thirdparty/pcre2/src/sljit/sljitNativeMIPS_32.c
@@ -367,7 +367,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
case SLJIT_MUL:
SLJIT_ASSERT(!(flags & SRC2_IMM));
- if (GET_FLAG_TYPE(op) != SLJIT_MUL_OVERFLOW) {
+ if (GET_FLAG_TYPE(op) != SLJIT_OVERFLOW) {
#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
return push_inst(compiler, MUL | S(src1) | T(src2) | D(dst), DR(dst));
#else /* SLJIT_MIPS_REV < 1 */
diff --git a/thirdparty/pcre2/src/sljit/sljitNativeMIPS_64.c b/thirdparty/pcre2/src/sljit/sljitNativeMIPS_64.c
index 5ab9b7d06b..1f22e49ed9 100644
--- a/thirdparty/pcre2/src/sljit/sljitNativeMIPS_64.c
+++ b/thirdparty/pcre2/src/sljit/sljitNativeMIPS_64.c
@@ -458,7 +458,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
case SLJIT_MUL:
SLJIT_ASSERT(!(flags & SRC2_IMM));
- if (GET_FLAG_TYPE(op) != SLJIT_MUL_OVERFLOW) {
+ if (GET_FLAG_TYPE(op) != SLJIT_OVERFLOW) {
#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6)
return push_inst(compiler, SELECT_OP(DMUL, MUL) | S(src1) | T(src2) | D(dst), DR(dst));
#elif (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
diff --git a/thirdparty/pcre2/src/sljit/sljitNativeMIPS_common.c b/thirdparty/pcre2/src/sljit/sljitNativeMIPS_common.c
index ecf4dac4c8..fd747695a7 100644
--- a/thirdparty/pcre2/src/sljit/sljitNativeMIPS_common.c
+++ b/thirdparty/pcre2/src/sljit/sljitNativeMIPS_common.c
@@ -1377,6 +1377,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
return emit_op(compiler, op, flags, dst, dstw, TMP_REG1, 0, src, srcw);
case SLJIT_NEG:
+ compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD_SUB;
return emit_op(compiler, SLJIT_SUB | GET_ALL_FLAGS(op), flags | IMM_OP, dst, dstw, SLJIT_IMM, 0, src, srcw);
case SLJIT_CLZ:
@@ -1424,13 +1425,16 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
switch (GET_OPCODE(op)) {
case SLJIT_ADD:
case SLJIT_ADDC:
+ compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD_SUB;
return emit_op(compiler, op, flags | CUMULATIVE_OP | IMM_OP, dst, dstw, src1, src1w, src2, src2w);
case SLJIT_SUB:
case SLJIT_SUBC:
+ compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD_SUB;
return emit_op(compiler, op, flags | IMM_OP, dst, dstw, src1, src1w, src2, src2w);
case SLJIT_MUL:
+ compiler->status_flags_state = 0;
return emit_op(compiler, op, flags | CUMULATIVE_OP, dst, dstw, src1, src1w, src2, src2w);
case SLJIT_AND:
@@ -1860,7 +1864,6 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
case SLJIT_SIG_LESS:
case SLJIT_SIG_GREATER:
case SLJIT_OVERFLOW:
- case SLJIT_MUL_OVERFLOW:
BR_Z(OTHER_FLAG);
break;
case SLJIT_GREATER_EQUAL:
@@ -1868,7 +1871,6 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
case SLJIT_SIG_GREATER_EQUAL:
case SLJIT_SIG_LESS_EQUAL:
case SLJIT_NOT_OVERFLOW:
- case SLJIT_MUL_NOT_OVERFLOW:
BR_NZ(OTHER_FLAG);
break;
case SLJIT_NOT_EQUAL_F64:
@@ -2127,8 +2129,12 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
FAIL_IF(push_inst(compiler, SLTIU | SA(EQUAL_FLAG) | TA(dst_ar) | IMM(1), dst_ar));
src_ar = dst_ar;
break;
- case SLJIT_MUL_OVERFLOW:
- case SLJIT_MUL_NOT_OVERFLOW:
+ case SLJIT_OVERFLOW:
+ case SLJIT_NOT_OVERFLOW:
+ if (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD_SUB) {
+ src_ar = OTHER_FLAG;
+ break;
+ }
FAIL_IF(push_inst(compiler, SLTIU | SA(OTHER_FLAG) | TA(dst_ar) | IMM(1), dst_ar));
src_ar = dst_ar;
type ^= 0x1; /* Flip type bit for the XORI below. */
@@ -2219,7 +2225,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compil
case SLJIT_SIG_LESS:
case SLJIT_SIG_GREATER:
case SLJIT_OVERFLOW:
- case SLJIT_MUL_OVERFLOW:
ins = MOVN | TA(OTHER_FLAG);
break;
case SLJIT_GREATER_EQUAL:
@@ -2227,7 +2232,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compil
case SLJIT_SIG_GREATER_EQUAL:
case SLJIT_SIG_LESS_EQUAL:
case SLJIT_NOT_OVERFLOW:
- case SLJIT_MUL_NOT_OVERFLOW:
ins = MOVZ | TA(OTHER_FLAG);
break;
case SLJIT_EQUAL_F64:
diff --git a/thirdparty/pcre2/src/sljit/sljitNativePPC_32.c b/thirdparty/pcre2/src/sljit/sljitNativePPC_32.c
index 7d9ec5338f..6ddb5508ec 100644
--- a/thirdparty/pcre2/src/sljit/sljitNativePPC_32.c
+++ b/thirdparty/pcre2/src/sljit/sljitNativePPC_32.c
@@ -119,9 +119,10 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
SLJIT_ASSERT(src2 == TMP_REG2);
return push_inst(compiler, ADDIC | D(dst) | A(src1) | compiler->imm);
}
+ SLJIT_ASSERT(!(flags & ALT_FORM4));
if (!(flags & ALT_SET_FLAGS))
return push_inst(compiler, ADD | D(dst) | A(src1) | B(src2));
- if (flags & ALT_FORM4)
+ if (flags & ALT_FORM5)
return push_inst(compiler, ADDC | RC(ALT_SET_FLAGS) | D(dst) | A(src1) | B(src2));
return push_inst(compiler, ADD | RC(flags) | D(dst) | A(src1) | B(src2));
@@ -143,24 +144,29 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
}
if (flags & ALT_FORM2) {
+ if (flags & ALT_FORM3) {
+ FAIL_IF(push_inst(compiler, CMPI | CRD(0) | A(src1) | compiler->imm));
+ if (!(flags & ALT_FORM4))
+ return SLJIT_SUCCESS;
+ return push_inst(compiler, ADDI | D(dst) | A(src1) | (-compiler->imm & 0xffff));
+ }
+ FAIL_IF(push_inst(compiler, CMP | CRD(0) | A(src1) | B(src2)));
+ if (!(flags & ALT_FORM4))
+ return SLJIT_SUCCESS;
+ return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
+ }
+
+ if (flags & ALT_FORM3) {
/* Setting XER SO is not enough, CR SO is also needed. */
return push_inst(compiler, SUBF | OE(ALT_SET_FLAGS) | RC(ALT_SET_FLAGS) | D(dst) | A(src2) | B(src1));
}
- if (flags & ALT_FORM3) {
+ if (flags & ALT_FORM4) {
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
SLJIT_ASSERT(src2 == TMP_REG2);
return push_inst(compiler, SUBFIC | D(dst) | A(src1) | compiler->imm);
}
- if (flags & ALT_FORM4) {
- if (flags & ALT_FORM5) {
- SLJIT_ASSERT(src2 == TMP_REG2);
- return push_inst(compiler, CMPI | CRD(0) | A(src1) | compiler->imm);
- }
- return push_inst(compiler, CMP | CRD(0) | A(src1) | B(src2));
- }
-
if (!(flags & ALT_SET_FLAGS))
return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
if (flags & ALT_FORM5)
diff --git a/thirdparty/pcre2/src/sljit/sljitNativePPC_64.c b/thirdparty/pcre2/src/sljit/sljitNativePPC_64.c
index 92147d2a5d..cbdf2dd8a2 100644
--- a/thirdparty/pcre2/src/sljit/sljitNativePPC_64.c
+++ b/thirdparty/pcre2/src/sljit/sljitNativePPC_64.c
@@ -252,10 +252,17 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
BIN_IMM_EXTS();
return push_inst(compiler, ADDIC | D(dst) | A(src1) | compiler->imm);
}
+ if (flags & ALT_FORM4) {
+ if (flags & ALT_FORM5)
+ FAIL_IF(push_inst(compiler, ADDI | D(dst) | A(src1) | compiler->imm));
+ else
+ FAIL_IF(push_inst(compiler, ADD | D(dst) | A(src1) | B(src2)));
+ return push_inst(compiler, CMPI | A(dst) | 0);
+ }
if (!(flags & ALT_SET_FLAGS))
return push_inst(compiler, ADD | D(dst) | A(src1) | B(src2));
BIN_EXTS();
- if (flags & ALT_FORM4)
+ if (flags & ALT_FORM5)
return push_inst(compiler, ADDC | RC(ALT_SET_FLAGS) | D(dst) | A(src1) | B(src2));
return push_inst(compiler, ADD | RC(flags) | D(dst) | A(src1) | B(src2));
@@ -278,6 +285,19 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
}
if (flags & ALT_FORM2) {
+ if (flags & ALT_FORM3) {
+ FAIL_IF(push_inst(compiler, CMPI | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | compiler->imm));
+ if (!(flags & ALT_FORM4))
+ return SLJIT_SUCCESS;
+ return push_inst(compiler, ADDI | D(dst) | A(src1) | (-compiler->imm & 0xffff));
+ }
+ FAIL_IF(push_inst(compiler, CMP | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | B(src2)));
+ if (!(flags & ALT_FORM4))
+ return SLJIT_SUCCESS;
+ return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
+ }
+
+ if (flags & ALT_FORM3) {
if (flags & ALT_SIGN_EXT) {
FAIL_IF(push_inst(compiler, RLDI(TMP_REG1, src1, 32, 31, 1)));
src1 = TMP_REG1;
@@ -291,20 +311,12 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
return SLJIT_SUCCESS;
}
- if (flags & ALT_FORM3) {
+ if (flags & ALT_FORM4) {
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
SLJIT_ASSERT(src2 == TMP_REG2);
return push_inst(compiler, SUBFIC | D(dst) | A(src1) | compiler->imm);
}
- if (flags & ALT_FORM4) {
- if (flags & ALT_FORM5) {
- SLJIT_ASSERT(src2 == TMP_REG2);
- return push_inst(compiler, CMPI | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | compiler->imm);
- }
- return push_inst(compiler, CMP | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | B(src2));
- }
-
if (!(flags & ALT_SET_FLAGS))
return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
BIN_EXTS();
diff --git a/thirdparty/pcre2/src/sljit/sljitNativePPC_common.c b/thirdparty/pcre2/src/sljit/sljitNativePPC_common.c
index d84562ce09..2174dbb07b 100644
--- a/thirdparty/pcre2/src/sljit/sljitNativePPC_common.c
+++ b/thirdparty/pcre2/src/sljit/sljitNativePPC_common.c
@@ -1324,6 +1324,25 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
((src) & SLJIT_IMM)
#endif
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+#define TEST_ADD_FORM1(op) \
+ (GET_FLAG_TYPE(op) == SLJIT_OVERFLOW \
+ || (op & (SLJIT_I32_OP | SLJIT_SET_Z | VARIABLE_FLAG_MASK)) == (SLJIT_I32_OP | SLJIT_SET_Z | SLJIT_SET_CARRY))
+#define TEST_SUB_FORM2(op) \
+ ((GET_FLAG_TYPE(op) >= SLJIT_SIG_LESS && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL) \
+ || (op & (SLJIT_I32_OP | SLJIT_SET_Z | VARIABLE_FLAG_MASK)) == (SLJIT_I32_OP | SLJIT_SET_Z))
+#define TEST_SUB_FORM3(op) \
+ (GET_FLAG_TYPE(op) == SLJIT_OVERFLOW \
+ || (op & (SLJIT_I32_OP | SLJIT_SET_Z)) == (SLJIT_I32_OP | SLJIT_SET_Z))
+#else
+#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
+
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,
@@ -1362,7 +1381,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
switch (GET_OPCODE(op)) {
case SLJIT_ADD:
- if (GET_FLAG_TYPE(op) == SLJIT_OVERFLOW)
+ 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)) {
@@ -1392,6 +1411,20 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2 | ALT_FORM4, dst, dstw, src2, src2w, TMP_REG2, 0);
}
}
+
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+ if ((op & (SLJIT_I32_OP | SLJIT_SET_Z)) == (SLJIT_I32_OP | SLJIT_SET_Z)) {
+ if (TEST_SL_IMM(src2, src2w)) {
+ compiler->imm = src2w & 0xffff;
+ return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM4 | ALT_FORM5, dst, dstw, src1, src1w, TMP_REG2, 0);
+ }
+ if (TEST_SL_IMM(src1, src1w)) {
+ compiler->imm = src1w & 0xffff;
+ return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM4 | ALT_FORM5, dst, dstw, src2, src2w, TMP_REG2, 0);
+ }
+ return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM4, dst, dstw, src1, src1w, src2, src2w);
+ }
+#endif
if (HAS_FLAGS(op)) {
if (TEST_SL_IMM(src2, src2w)) {
compiler->imm = src2w & 0xffff;
@@ -1402,7 +1435,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_FORM4 : 0), dst, dstw, src1, src1w, src2, src2w);
+ 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);
case SLJIT_ADDC:
return emit_op(compiler, SLJIT_ADDC, flags, dst, dstw, src1, src1w, src2, src2w);
@@ -1424,18 +1457,36 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM1 | ALT_FORM3, dst, dstw, src1, src1w, src2, src2w);
}
- if (GET_FLAG_TYPE(op) == SLJIT_OVERFLOW)
+ if (dst == SLJIT_UNUSED && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL) {
+ if (TEST_SL_IMM(src2, src2w)) {
+ compiler->imm = src2w & 0xffff;
+ return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM2 | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);
+ }
return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM2, dst, dstw, src1, src1w, src2, src2w);
+ }
- if (!HAS_FLAGS(op) && ((src1 | src2) & SLJIT_IMM)) {
- if (TEST_SL_IMM(src2, -src2w)) {
- compiler->imm = (-src2w) & 0xffff;
- return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0);
- }
- if (TEST_SL_IMM(src1, src1w)) {
- compiler->imm = src1w & 0xffff;
- return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM3, dst, dstw, src2, src2w, TMP_REG2, 0);
+ if (TEST_SUB_FORM2(op)) {
+ if ((src2 & SLJIT_IMM) && src2w >= -SIMM_MAX && src2w <= SIMM_MAX) {
+ compiler->imm = src2w & 0xffff;
+ return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM2 | ALT_FORM3 | ALT_FORM4, dst, dstw, src1, src1w, TMP_REG2, 0);
}
+ return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM2 | ALT_FORM4, dst, dstw, src1, src1w, src2, src2w);
+ }
+
+ if (TEST_SUB_FORM3(op))
+ return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM3, dst, dstw, src1, src1w, src2, src2w);
+
+ if (TEST_SL_IMM(src2, -src2w)) {
+ compiler->imm = (-src2w) & 0xffff;
+ return emit_op(compiler, SLJIT_ADD, flags | (!HAS_FLAGS(op) ? ALT_FORM2 : ALT_FORM3), dst, dstw, src1, src1w, TMP_REG2, 0);
+ }
+
+ if (TEST_SL_IMM(src1, src1w) && !(op & SLJIT_SET_Z)) {
+ compiler->imm = src1w & 0xffff;
+ return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM4, dst, dstw, src2, src2w, TMP_REG2, 0);
+ }
+
+ if (!HAS_FLAGS(op)) {
if (TEST_SH_IMM(src2, -src2w)) {
compiler->imm = ((-src2w) >> 16) & 0xffff;
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2 | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);
@@ -1447,18 +1498,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
}
}
- if (dst == SLJIT_UNUSED && GET_FLAG_TYPE(op) != GET_FLAG_TYPE(SLJIT_SET_CARRY)) {
- if (TEST_SL_IMM(src2, src2w)) {
- compiler->imm = src2w & 0xffff;
- return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM4 | ALT_FORM5, dst, dstw, src1, src1w, TMP_REG2, 0);
- }
- return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM4, dst, dstw, src1, src1w, src2, src2w);
- }
-
- if (TEST_SL_IMM(src2, -src2w)) {
- compiler->imm = (-src2w) & 0xffff;
- return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);
- }
/* We know ALT_SIGN_EXT is set if it is an SLJIT_I32_OP 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);
@@ -1536,6 +1575,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
return SLJIT_SUCCESS;
}
+#undef TEST_ADD_FORM1
+#undef TEST_SUB_FORM2
+#undef TEST_SUB_FORM3
+
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op,
sljit_s32 src, sljit_sw srcw)
{
@@ -1941,11 +1984,9 @@ static sljit_ins get_bo_bi_flags(sljit_s32 type)
return (4 << 21) | ((4 + 1) << 16);
case SLJIT_OVERFLOW:
- case SLJIT_MUL_OVERFLOW:
return (12 << 21) | (3 << 16);
case SLJIT_NOT_OVERFLOW:
- case SLJIT_MUL_NOT_OVERFLOW:
return (4 << 21) | (3 << 16);
case SLJIT_EQUAL_F64:
@@ -2143,12 +2184,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
break;
case SLJIT_OVERFLOW:
- case SLJIT_MUL_OVERFLOW:
cr_bit = 3;
break;
case SLJIT_NOT_OVERFLOW:
- case SLJIT_MUL_NOT_OVERFLOW:
cr_bit = 3;
invert = 1;
break;
diff --git a/thirdparty/pcre2/src/sljit/sljitNativeS390X.c b/thirdparty/pcre2/src/sljit/sljitNativeS390X.c
index a8b65112d4..716491ec72 100644
--- a/thirdparty/pcre2/src/sljit/sljitNativeS390X.c
+++ b/thirdparty/pcre2/src/sljit/sljitNativeS390X.c
@@ -42,10 +42,10 @@ SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void)
typedef sljit_uw sljit_ins;
/* Instruction tags (most significant halfword). */
-const sljit_ins sljit_ins_const = (sljit_ins)1 << 48;
+static const sljit_ins sljit_ins_const = (sljit_ins)1 << 48;
static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 4] = {
- 14, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15, 0, 1
+ 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15, 0, 1
};
/* there are also a[2-15] available, but they are slower to access and
@@ -66,22 +66,22 @@ typedef sljit_uw sljit_gpr;
* will be retired ASAP (TODO: carenas)
*/
-const sljit_gpr r0 = 0; /* reg_map[SLJIT_NUMBER_OF_REGISTERS + 2]: 0 in address calculations; reserved */
-const sljit_gpr r1 = 1; /* reg_map[SLJIT_NUMBER_OF_REGISTERS + 3]: reserved */
-const sljit_gpr r2 = 2; /* reg_map[1]: 1st argument */
-const sljit_gpr r3 = 3; /* reg_map[2]: 2nd argument */
-const sljit_gpr r4 = 4; /* reg_map[3]: 3rd argument */
-const sljit_gpr r5 = 5; /* reg_map[4]: 4th argument */
-const sljit_gpr r6 = 6; /* reg_map[5]: 5th argument; 1st saved register */
-const sljit_gpr r7 = 7; /* reg_map[6] */
-const sljit_gpr r8 = 8; /* reg_map[7] */
-const sljit_gpr r9 = 9; /* reg_map[8] */
-const sljit_gpr r10 = 10; /* reg_map[9] */
-const sljit_gpr r11 = 11; /* reg_map[10] */
-const sljit_gpr r12 = 12; /* reg_map[11]: GOT */
-const sljit_gpr r13 = 13; /* reg_map[12]: Literal Pool pointer */
-const sljit_gpr r14 = 14; /* reg_map[0]: return address and flag register */
-const sljit_gpr r15 = 15; /* reg_map[SLJIT_NUMBER_OF_REGISTERS + 1]: stack pointer */
+static const sljit_gpr r0 = 0; /* reg_map[SLJIT_NUMBER_OF_REGISTERS + 2]: 0 in address calculations; reserved */
+static const sljit_gpr r1 = 1; /* reg_map[SLJIT_NUMBER_OF_REGISTERS + 3]: reserved */
+static const sljit_gpr r2 = 2; /* reg_map[1]: 1st argument */
+static const sljit_gpr r3 = 3; /* reg_map[2]: 2nd argument */
+static const sljit_gpr r4 = 4; /* reg_map[3]: 3rd argument */
+static const sljit_gpr r5 = 5; /* reg_map[4]: 4th argument */
+static const sljit_gpr r6 = 6; /* reg_map[5]: 5th argument; 1st saved register */
+static const sljit_gpr r7 = 7; /* reg_map[6] */
+static const sljit_gpr r8 = 8; /* reg_map[7] */
+static const sljit_gpr r9 = 9; /* reg_map[8] */
+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 r15 = 15; /* reg_map[SLJIT_NUMBER_OF_REGISTERS + 1]: stack pointer */
/* WARNING: r12 and r13 shouldn't be used as per ABI recommendation */
/* TODO(carenas): r12 might conflict in PIC code, reserve? */
@@ -100,8 +100,8 @@ const sljit_gpr r15 = 15; /* reg_map[SLJIT_NUMBER_OF_REGISTERS + 1]: stack point
/* Link registers. The normal link register is r14, but since
we use that for flags we need to use r0 instead to do fast
calls so that flags are preserved. */
-const sljit_gpr link_r = 14; /* r14 */
-const sljit_gpr fast_link_r = 0; /* r0 */
+static const sljit_gpr link_r = 14; /* r14 */
+static const sljit_gpr fast_link_r = 0; /* r0 */
/* Flag register layout:
@@ -110,7 +110,7 @@ const sljit_gpr fast_link_r = 0; /* r0 */
| ZERO | 0 | 0 | C C |///////|
+---------------+---+---+-------+-------+
*/
-const sljit_gpr flag_r = 14; /* r14 */
+static const sljit_gpr flag_r = 14; /* r14 */
struct sljit_s390x_const {
struct sljit_const const_; /* must be first */
@@ -120,8 +120,7 @@ struct sljit_s390x_const {
/* Convert SLJIT register to hardware register. */
static SLJIT_INLINE sljit_gpr gpr(sljit_s32 r)
{
- SLJIT_ASSERT(r != SLJIT_UNUSED);
- SLJIT_ASSERT(r < (sljit_s32)(sizeof(reg_map) / sizeof(reg_map[0])));
+ SLJIT_ASSERT(r >= 0 && r < (sljit_s32)(sizeof(reg_map) / sizeof(reg_map[0])));
return reg_map[r];
}
@@ -172,51 +171,93 @@ static sljit_s32 encode_inst(void **ptr, sljit_ins ins)
return SLJIT_SUCCESS;
}
+#define SLJIT_ADD_SUB_NO_COMPARE(status_flags_state) \
+ (((status_flags_state) & (SLJIT_CURRENT_FLAGS_ADD_SUB | SLJIT_CURRENT_FLAGS_COMPARE)) == SLJIT_CURRENT_FLAGS_ADD_SUB)
+
/* Map the given type to a 4-bit condition code mask. */
-static SLJIT_INLINE sljit_u8 get_cc(sljit_s32 type) {
- const sljit_u8 eq = 1 << 3; /* equal {,to zero} */
- const sljit_u8 lt = 1 << 2; /* less than {,zero} */
- const sljit_u8 gt = 1 << 1; /* greater than {,zero} */
- const sljit_u8 ov = 1 << 0; /* {overflow,NaN} */
+static SLJIT_INLINE sljit_u8 get_cc(struct sljit_compiler *compiler, sljit_s32 type) {
+ const sljit_u8 cc0 = 1 << 3; /* equal {,to zero} */
+ const sljit_u8 cc1 = 1 << 2; /* less than {,zero} */
+ const sljit_u8 cc2 = 1 << 1; /* greater than {,zero} */
+ const sljit_u8 cc3 = 1 << 0; /* {overflow,NaN} */
switch (type) {
case SLJIT_EQUAL:
+ if (SLJIT_ADD_SUB_NO_COMPARE(compiler->status_flags_state)) {
+ sljit_s32 type = GET_FLAG_TYPE(compiler->status_flags_state);
+ if (type >= SLJIT_SIG_LESS && type <= SLJIT_SIG_LESS_EQUAL)
+ return cc0;
+ if (type == SLJIT_OVERFLOW)
+ return (cc0 | cc3);
+ return (cc0 | cc2);
+ }
+
case SLJIT_EQUAL_F64:
- return eq;
+ return cc0;
case SLJIT_NOT_EQUAL:
+ if (SLJIT_ADD_SUB_NO_COMPARE(compiler->status_flags_state)) {
+ sljit_s32 type = GET_FLAG_TYPE(compiler->status_flags_state);
+ if (type >= SLJIT_SIG_LESS && type <= SLJIT_SIG_LESS_EQUAL)
+ return (cc1 | cc2 | cc3);
+ if (type == SLJIT_OVERFLOW)
+ return (cc1 | cc2);
+ return (cc1 | cc3);
+ }
+
case SLJIT_NOT_EQUAL_F64:
- return ~eq;
+ return (cc1 | cc2 | cc3);
case SLJIT_LESS:
+ return cc1;
+
+ case SLJIT_GREATER_EQUAL:
+ return (cc0 | cc2 | cc3);
+
+ case SLJIT_GREATER:
+ if (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_COMPARE)
+ return cc2;
+ return cc3;
+
+ case SLJIT_LESS_EQUAL:
+ if (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_COMPARE)
+ return (cc0 | cc1);
+ return (cc0 | cc1 | cc2);
+
case SLJIT_SIG_LESS:
case SLJIT_LESS_F64:
- return lt;
+ return cc1;
- case SLJIT_LESS_EQUAL:
case SLJIT_SIG_LESS_EQUAL:
case SLJIT_LESS_EQUAL_F64:
- return (lt | eq);
+ return (cc0 | cc1);
- case SLJIT_GREATER:
case SLJIT_SIG_GREATER:
- case SLJIT_GREATER_F64:
- return gt;
+ /* Overflow is considered greater, see SLJIT_SUB. */
+ return cc2 | cc3;
- case SLJIT_GREATER_EQUAL:
case SLJIT_SIG_GREATER_EQUAL:
- case SLJIT_GREATER_EQUAL_F64:
- return (gt | eq);
+ return (cc0 | cc2 | cc3);
case SLJIT_OVERFLOW:
- case SLJIT_MUL_OVERFLOW:
+ if (compiler->status_flags_state & SLJIT_SET_Z)
+ return (cc2 | cc3);
+
case SLJIT_UNORDERED_F64:
- return ov;
+ return cc3;
case SLJIT_NOT_OVERFLOW:
- case SLJIT_MUL_NOT_OVERFLOW:
+ if (compiler->status_flags_state & SLJIT_SET_Z)
+ return (cc0 | cc1);
+
case SLJIT_ORDERED_F64:
- return ~ov;
+ return (cc0 | cc1 | cc2);
+
+ case SLJIT_GREATER_F64:
+ return cc2;
+
+ case SLJIT_GREATER_EQUAL_F64:
+ return (cc0 | cc2);
}
SLJIT_UNREACHABLE();
@@ -346,19 +387,20 @@ HAVE_FACILITY(have_misc2, MISCELLANEOUS_INSTRUCTION_EXTENSIONS_2_FACILITY)
#define is_u32(d) (0 <= (d) && (d) <= 0xffffffffL)
#define CHECK_SIGNED(v, bitlen) \
- ((v) == (((v) << (sizeof(v) * 8 - bitlen)) >> (sizeof(v) * 8 - bitlen)))
+ ((v) >= -(1 << ((bitlen) - 1)) && (v) < (1 << ((bitlen) - 1)))
+#define is_s8(d) CHECK_SIGNED((d), 8)
#define is_s16(d) CHECK_SIGNED((d), 16)
#define is_s20(d) CHECK_SIGNED((d), 20)
-#define is_s32(d) CHECK_SIGNED((d), 32)
+#define is_s32(d) ((d) == (sljit_s32)(d))
-static SLJIT_INLINE sljit_uw disp_s20(sljit_s32 d)
+static SLJIT_INLINE sljit_ins disp_s20(sljit_s32 d)
{
+ SLJIT_ASSERT(is_s20(d));
+
sljit_uw dh = (d >> 12) & 0xff;
sljit_uw dl = (d << 8) & 0xfff00;
-
- SLJIT_ASSERT(is_s20(d));
- return dh | dl;
+ return (dh | dl) << 8;
}
/* TODO(carenas): variadic macro is not strictly needed */
@@ -372,12 +414,6 @@ SLJIT_S390X_INSTRUCTION(name, sljit_gpr dst, sljit_gpr src) \
return (pattern) | ((dst & 0xf) << 4) | (src & 0xf); \
}
-/* ADD */
-SLJIT_S390X_RR(ar, 0x1a00)
-
-/* ADD LOGICAL */
-SLJIT_S390X_RR(alr, 0x1e00)
-
/* AND */
SLJIT_S390X_RR(nr, 0x1400)
@@ -387,12 +423,6 @@ SLJIT_S390X_RR(basr, 0x0d00)
/* BRANCH ON CONDITION */
SLJIT_S390X_RR(bcr, 0x0700) /* TODO(mundaym): type for mask? */
-/* COMPARE */
-SLJIT_S390X_RR(cr, 0x1900)
-
-/* COMPARE LOGICAL */
-SLJIT_S390X_RR(clr, 0x1500)
-
/* DIVIDE */
SLJIT_S390X_RR(dr, 0x1d00)
@@ -408,12 +438,6 @@ SLJIT_S390X_RR(lcr, 0x1300)
/* OR */
SLJIT_S390X_RR(or, 0x1600)
-/* SUBTRACT */
-SLJIT_S390X_RR(sr, 0x1b00)
-
-/* SUBTRACT LOGICAL */
-SLJIT_S390X_RR(slr, 0x1f00)
-
#undef SLJIT_S390X_RR
/* RRE form instructions */
@@ -423,25 +447,9 @@ SLJIT_S390X_INSTRUCTION(name, sljit_gpr dst, sljit_gpr src) \
return (pattern) | ((dst & 0xf) << 4) | (src & 0xf); \
}
-/* ADD */
-SLJIT_S390X_RRE(agr, 0xb9080000)
-
-/* ADD LOGICAL */
-SLJIT_S390X_RRE(algr, 0xb90a0000)
-
-/* ADD LOGICAL WITH CARRY */
-SLJIT_S390X_RRE(alcr, 0xb9980000)
-SLJIT_S390X_RRE(alcgr, 0xb9880000)
-
/* AND */
SLJIT_S390X_RRE(ngr, 0xb9800000)
-/* COMPARE */
-SLJIT_S390X_RRE(cgr, 0xb9200000)
-
-/* COMPARE LOGICAL */
-SLJIT_S390X_RRE(clgr, 0xb9210000)
-
/* DIVIDE LOGICAL */
SLJIT_S390X_RRE(dlr, 0xb9970000)
SLJIT_S390X_RRE(dlgr, 0xb9870000)
@@ -482,8 +490,6 @@ SLJIT_S390X_RRE(llghr, 0xb9850000)
SLJIT_S390X_RRE(mlgr, 0xb9860000)
/* MULTIPLY SINGLE */
-SLJIT_S390X_RRE(msr, 0xb2520000)
-SLJIT_S390X_RRE(msgr, 0xb90c0000)
SLJIT_S390X_RRE(msgfr, 0xb91c0000)
/* OR */
@@ -492,13 +498,6 @@ SLJIT_S390X_RRE(ogr, 0xb9810000)
/* SUBTRACT */
SLJIT_S390X_RRE(sgr, 0xb9090000)
-/* SUBTRACT LOGICAL */
-SLJIT_S390X_RRE(slgr, 0xb90b0000)
-
-/* SUBTRACT LOGICAL WITH BORROW */
-SLJIT_S390X_RRE(slbr, 0xb9990000)
-SLJIT_S390X_RRE(slbgr, 0xb9890000)
-
#undef SLJIT_S390X_RRE
/* RI-a form instructions */
@@ -509,13 +508,8 @@ SLJIT_S390X_INSTRUCTION(name, sljit_gpr reg, imm_type imm) \
}
/* ADD HALFWORD IMMEDIATE */
-SLJIT_S390X_RIA(ahi, 0xa70a0000, sljit_s16)
SLJIT_S390X_RIA(aghi, 0xa70b0000, sljit_s16)
-/* COMPARE HALFWORD IMMEDIATE */
-SLJIT_S390X_RIA(chi, 0xa70e0000, sljit_s16)
-SLJIT_S390X_RIA(cghi, 0xa70f0000, sljit_s16)
-
/* LOAD HALFWORD IMMEDIATE */
SLJIT_S390X_RIA(lhi, 0xa7080000, sljit_s16)
SLJIT_S390X_RIA(lghi, 0xa7090000, sljit_s16)
@@ -533,9 +527,6 @@ SLJIT_S390X_RIA(mghi, 0xa70d0000, sljit_s16)
/* OR IMMEDIATE */
SLJIT_S390X_RIA(oilh, 0xa50a0000, sljit_u16)
-/* TEST UNDER MASK */
-SLJIT_S390X_RIA(tmlh, 0xa7000000, sljit_u16)
-
#undef SLJIT_S390X_RIA
/* RIL-a form instructions (requires extended immediate facility) */
@@ -547,30 +538,13 @@ SLJIT_S390X_INSTRUCTION(name, sljit_gpr reg, imm_type imm) \
}
/* ADD IMMEDIATE */
-SLJIT_S390X_RILA(afi, 0xc20900000000, sljit_s32)
SLJIT_S390X_RILA(agfi, 0xc20800000000, sljit_s32)
/* ADD IMMEDIATE HIGH */
SLJIT_S390X_RILA(aih, 0xcc0800000000, sljit_s32) /* TODO(mundaym): high-word facility? */
-/* ADD LOGICAL IMMEDIATE */
-SLJIT_S390X_RILA(alfi, 0xc20b00000000, sljit_u32)
-SLJIT_S390X_RILA(algfi, 0xc20a00000000, sljit_u32)
-
/* AND IMMEDIATE */
SLJIT_S390X_RILA(nihf, 0xc00a00000000, sljit_u32)
-SLJIT_S390X_RILA(nilf, 0xc00b00000000, sljit_u32)
-
-/* COMPARE IMMEDIATE */
-SLJIT_S390X_RILA(cfi, 0xc20d00000000, sljit_s32)
-SLJIT_S390X_RILA(cgfi, 0xc20c00000000, sljit_s32)
-
-/* COMPARE IMMEDIATE HIGH */
-SLJIT_S390X_RILA(cih, 0xcc0d00000000, sljit_s32) /* TODO(mundaym): high-word facility? */
-
-/* COMPARE LOGICAL IMMEDIATE */
-SLJIT_S390X_RILA(clfi, 0xc20f00000000, sljit_u32)
-SLJIT_S390X_RILA(clgfi, 0xc20e00000000, sljit_u32)
/* EXCLUSIVE OR IMMEDIATE */
SLJIT_S390X_RILA(xilf, 0xc00700000000, sljit_u32)
@@ -586,8 +560,8 @@ SLJIT_S390X_RILA(lgfi, 0xc00100000000, sljit_s32)
SLJIT_S390X_RILA(llihf, 0xc00e00000000, sljit_u32)
SLJIT_S390X_RILA(llilf, 0xc00f00000000, sljit_u32)
-/* OR IMMEDIATE */
-SLJIT_S390X_RILA(oilf, 0xc00d00000000, sljit_u32)
+/* SUBTRACT LOGICAL IMMEDIATE */
+SLJIT_S390X_RILA(slfi, 0xc20500000000, sljit_u32)
#undef SLJIT_S390X_RILA
@@ -606,18 +580,6 @@ SLJIT_S390X_INSTRUCTION(name, sljit_gpr r, sljit_u16 d, sljit_gpr x, sljit_gpr b
return (pattern) | ri | xi | bi | di; \
}
-/* ADD */
-SLJIT_S390X_RXA(a, 0x5a000000)
-
-/* ADD LOGICAL */
-SLJIT_S390X_RXA(al, 0x5e000000)
-
-/* AND */
-SLJIT_S390X_RXA(n, 0x54000000)
-
-/* EXCLUSIVE OR */
-SLJIT_S390X_RXA(x, 0x57000000)
-
/* LOAD */
SLJIT_S390X_RXA(l, 0x58000000)
@@ -630,9 +592,6 @@ SLJIT_S390X_RXA(lh, 0x48000000)
/* MULTIPLY SINGLE */
SLJIT_S390X_RXA(ms, 0x71000000)
-/* OR */
-SLJIT_S390X_RXA(o, 0x56000000)
-
/* STORE */
SLJIT_S390X_RXA(st, 0x50000000)
@@ -642,12 +601,6 @@ SLJIT_S390X_RXA(stc, 0x42000000)
/* STORE HALFWORD */
SLJIT_S390X_RXA(sth, 0x40000000)
-/* SUBTRACT */
-SLJIT_S390X_RXA(s, 0x5b000000)
-
-/* SUBTRACT LOGICAL */
-SLJIT_S390X_RXA(sl, 0x5f000000)
-
#undef SLJIT_S390X_RXA
/* RXY-a instructions */
@@ -660,31 +613,11 @@ SLJIT_S390X_INSTRUCTION(name, sljit_gpr r, sljit_s32 d, sljit_gpr x, sljit_gpr b
ri = (sljit_ins)(r & 0xf) << 36; \
xi = (sljit_ins)(x & 0xf) << 32; \
bi = (sljit_ins)(b & 0xf) << 28; \
- di = (sljit_ins)disp_s20(d) << 8; \
+ di = disp_s20(d); \
\
return (pattern) | ri | xi | bi | di; \
}
-/* ADD */
-SLJIT_S390X_RXYA(ay, 0xe3000000005a, have_ldisp())
-SLJIT_S390X_RXYA(ag, 0xe30000000008, 1)
-
-/* ADD LOGICAL */
-SLJIT_S390X_RXYA(aly, 0xe3000000005e, have_ldisp())
-SLJIT_S390X_RXYA(alg, 0xe3000000000a, 1)
-
-/* ADD LOGICAL WITH CARRY */
-SLJIT_S390X_RXYA(alc, 0xe30000000098, 1)
-SLJIT_S390X_RXYA(alcg, 0xe30000000088, 1)
-
-/* AND */
-SLJIT_S390X_RXYA(ny, 0xe30000000054, have_ldisp())
-SLJIT_S390X_RXYA(ng, 0xe30000000080, 1)
-
-/* EXCLUSIVE OR */
-SLJIT_S390X_RXYA(xy, 0xe30000000057, have_ldisp())
-SLJIT_S390X_RXYA(xg, 0xe30000000082, 1)
-
/* LOAD */
SLJIT_S390X_RXYA(ly, 0xe30000000058, have_ldisp())
SLJIT_S390X_RXYA(lg, 0xe30000000004, 1)
@@ -713,10 +646,6 @@ SLJIT_S390X_RXYA(llgh, 0xe30000000091, 1)
SLJIT_S390X_RXYA(msy, 0xe30000000051, have_ldisp())
SLJIT_S390X_RXYA(msg, 0xe3000000000c, 1)
-/* OR */
-SLJIT_S390X_RXYA(oy, 0xe30000000056, have_ldisp())
-SLJIT_S390X_RXYA(og, 0xe30000000081, 1)
-
/* STORE */
SLJIT_S390X_RXYA(sty, 0xe30000000050, have_ldisp())
SLJIT_S390X_RXYA(stg, 0xe30000000024, 1)
@@ -727,41 +656,8 @@ SLJIT_S390X_RXYA(stcy, 0xe30000000072, have_ldisp())
/* STORE HALFWORD */
SLJIT_S390X_RXYA(sthy, 0xe30000000070, have_ldisp())
-/* SUBTRACT */
-SLJIT_S390X_RXYA(sy, 0xe3000000005b, have_ldisp())
-SLJIT_S390X_RXYA(sg, 0xe30000000009, 1)
-
-/* SUBTRACT LOGICAL */
-SLJIT_S390X_RXYA(sly, 0xe3000000005f, have_ldisp())
-SLJIT_S390X_RXYA(slg, 0xe3000000000b, 1)
-
-/* SUBTRACT LOGICAL WITH BORROW */
-SLJIT_S390X_RXYA(slb, 0xe30000000099, 1)
-SLJIT_S390X_RXYA(slbg, 0xe30000000089, 1)
-
#undef SLJIT_S390X_RXYA
-/* RS-a instructions */
-#define SLJIT_S390X_RSA(name, pattern) \
-SLJIT_S390X_INSTRUCTION(name, sljit_gpr reg, sljit_sw d, sljit_gpr b) \
-{ \
- sljit_ins r1 = (sljit_ins)(reg & 0xf) << 20; \
- sljit_ins b2 = (sljit_ins)(b & 0xf) << 12; \
- sljit_ins d2 = (sljit_ins)(d & 0xfff); \
- return (pattern) | r1 | b2 | d2; \
-}
-
-/* SHIFT LEFT SINGLE LOGICAL */
-SLJIT_S390X_RSA(sll, 0x89000000)
-
-/* SHIFT RIGHT SINGLE */
-SLJIT_S390X_RSA(sra, 0x8a000000)
-
-/* SHIFT RIGHT SINGLE LOGICAL */
-SLJIT_S390X_RSA(srl, 0x88000000)
-
-#undef SLJIT_S390X_RSA
-
/* RSY-a instructions */
#define SLJIT_S390X_RSYA(name, pattern, cond) \
SLJIT_S390X_INSTRUCTION(name, sljit_gpr dst, sljit_gpr src, sljit_sw d, sljit_gpr b) \
@@ -772,7 +668,7 @@ SLJIT_S390X_INSTRUCTION(name, sljit_gpr dst, sljit_gpr src, sljit_sw d, sljit_gp
r1 = (sljit_ins)(dst & 0xf) << 36; \
r3 = (sljit_ins)(src & 0xf) << 32; \
b2 = (sljit_ins)(b & 0xf) << 28; \
- d2 = (sljit_ins)disp_s20(d) << 8; \
+ d2 = disp_s20(d); \
\
return (pattern) | r1 | r3 | b2 | d2; \
}
@@ -786,9 +682,6 @@ SLJIT_S390X_RSYA(sllg, 0xeb000000000d, 1)
/* SHIFT RIGHT SINGLE */
SLJIT_S390X_RSYA(srag, 0xeb000000000a, 1)
-/* SHIFT RIGHT SINGLE LOGICAL */
-SLJIT_S390X_RSYA(srlg, 0xeb000000000c, 1)
-
/* STORE MULTIPLE */
SLJIT_S390X_RSYA(stmg, 0xeb0000000024, 1)
@@ -831,26 +724,6 @@ SLJIT_S390X_RIEF(risbhg, 0xec000000005d)
#undef SLJIT_S390X_RIEF
-/* RRF-a instructions */
-#define SLJIT_S390X_RRFA(name, pattern, cond) \
-SLJIT_S390X_INSTRUCTION(name, sljit_gpr dst, sljit_gpr src1, sljit_gpr src2) \
-{ \
- sljit_ins r1, r2, r3; \
-\
- SLJIT_ASSERT(cond); \
- r1 = (sljit_ins)(dst & 0xf) << 4; \
- r2 = (sljit_ins)(src1 & 0xf); \
- r3 = (sljit_ins)(src2 & 0xf) << 12; \
-\
- return (pattern) | r3 | r1 | r2; \
-}
-
-/* MULTIPLY */
-SLJIT_S390X_RRFA(msrkc, 0xb9fd0000, have_misc2())
-SLJIT_S390X_RRFA(msgrkc, 0xb9ed0000, have_misc2())
-
-#undef SLJIT_S390X_RRFA
-
/* RRF-c instructions (require load/store-on-condition 1 facility) */
#define SLJIT_S390X_RRFC(name, pattern) \
SLJIT_S390X_INSTRUCTION(name, sljit_gpr dst, sljit_gpr src, sljit_uw mask) \
@@ -919,6 +792,13 @@ SLJIT_S390X_INSTRUCTION(br, sljit_gpr target)
return 0x07f0 | target;
}
+SLJIT_S390X_INSTRUCTION(brc, sljit_uw mask, sljit_sw target)
+{
+ sljit_ins m1 = (sljit_ins)(mask & 0xf) << 20;
+ sljit_ins ri2 = (sljit_ins)target & 0xffff;
+ return 0xa7040000L | m1 | ri2;
+}
+
SLJIT_S390X_INSTRUCTION(brcl, sljit_uw mask, sljit_sw target)
{
sljit_ins m1 = (sljit_ins)(mask & 0xf) << 36;
@@ -940,6 +820,12 @@ SLJIT_S390X_INSTRUCTION(ipm, sljit_gpr dst)
return 0xb2220000 | ((sljit_ins)(dst & 0xf) << 4);
}
+/* SET PROGRAM MASK */
+SLJIT_S390X_INSTRUCTION(spm, sljit_gpr dst)
+{
+ return 0x0400 | ((sljit_ins)(dst & 0xf) << 4);
+}
+
/* ROTATE THEN INSERT SELECTED BITS HIGH (ZERO) */
SLJIT_S390X_INSTRUCTION(risbhgz, sljit_gpr dst, sljit_gpr src, sljit_u8 start, sljit_u8 end, sljit_u8 rot)
{
@@ -948,30 +834,20 @@ SLJIT_S390X_INSTRUCTION(risbhgz, sljit_gpr dst, sljit_gpr src, sljit_u8 start, s
#undef SLJIT_S390X_INSTRUCTION
-/* load condition code as needed to match type */
-static sljit_s32 push_load_cc(struct sljit_compiler *compiler, sljit_s32 type)
+static sljit_s32 update_zero_overflow(struct sljit_compiler *compiler, sljit_s32 op, sljit_gpr dst_r)
{
- type &= ~SLJIT_I32_OP;
- switch (type) {
- case SLJIT_ZERO:
- case SLJIT_NOT_ZERO:
- return push_inst(compiler, cih(flag_r, 0));
- break;
- default:
- return push_inst(compiler, tmlh(flag_r, 0x3000));
- break;
- }
- return SLJIT_SUCCESS;
-}
-
-static sljit_s32 push_store_zero_flag(struct sljit_compiler *compiler, sljit_s32 op, sljit_gpr source)
-{
- /* insert low 32-bits into high 32-bits of flag register */
- FAIL_IF(push_inst(compiler, risbhgz(flag_r, source, 0, 31, 32)));
- if (!(op & SLJIT_I32_OP)) {
- /* OR high 32-bits with high 32-bits of flag register */
- return push_inst(compiler, rosbg(flag_r, source, 0, 31, 0));
- }
+ /* Condition codes: bits 18 and 19.
+ Transformation:
+ 0 (zero and no overflow) : unchanged
+ 1 (non-zero and no overflow) : unchanged
+ 2 (zero and overflow) : decreased by 1
+ 3 (non-zero and overflow) : decreased by 1 if non-zero */
+ FAIL_IF(push_inst(compiler, brc(0xc, 2 + 2 + ((op & SLJIT_I32_OP) ? 1 : 2) + 2 + 3 + 1)));
+ FAIL_IF(push_inst(compiler, ipm(flag_r)));
+ FAIL_IF(push_inst(compiler, (op & SLJIT_I32_OP) ? or(dst_r, dst_r) : ogr(dst_r, dst_r)));
+ FAIL_IF(push_inst(compiler, brc(0x8, 2 + 3)));
+ FAIL_IF(push_inst(compiler, slfi(flag_r, 0x10000000)));
+ FAIL_IF(push_inst(compiler, spm(flag_r)));
return SLJIT_SUCCESS;
}
@@ -1088,18 +964,19 @@ static sljit_s32 make_addr_bx(struct sljit_compiler *compiler,
#define WHEN(cond, r, i1, i2, addr) \
(cond) ? EVAL(i1, r, addr) : EVAL(i2, r, addr)
+/* May clobber tmp1. */
static sljit_s32 load_word(struct sljit_compiler *compiler, sljit_gpr dst,
sljit_s32 src, sljit_sw srcw,
- sljit_gpr tmp /* clobbered */, sljit_s32 is_32bit)
+ sljit_s32 is_32bit)
{
struct addr addr;
sljit_ins ins;
SLJIT_ASSERT(src & SLJIT_MEM);
if (have_ldisp() || !is_32bit)
- FAIL_IF(make_addr_bxy(compiler, &addr, src, srcw, tmp));
+ FAIL_IF(make_addr_bxy(compiler, &addr, src, srcw, tmp1));
else
- FAIL_IF(make_addr_bx(compiler, &addr, src, srcw, tmp));
+ FAIL_IF(make_addr_bx(compiler, &addr, src, srcw, tmp1));
if (is_32bit)
ins = WHEN(is_u12(addr.offset), dst, l, ly, addr);
@@ -1109,18 +986,19 @@ static sljit_s32 load_word(struct sljit_compiler *compiler, sljit_gpr dst,
return push_inst(compiler, ins);
}
+/* May clobber tmp1. */
static sljit_s32 store_word(struct sljit_compiler *compiler, sljit_gpr src,
sljit_s32 dst, sljit_sw dstw,
- sljit_gpr tmp /* clobbered */, sljit_s32 is_32bit)
+ sljit_s32 is_32bit)
{
struct addr addr;
sljit_ins ins;
SLJIT_ASSERT(dst & SLJIT_MEM);
if (have_ldisp() || !is_32bit)
- FAIL_IF(make_addr_bxy(compiler, &addr, dst, dstw, tmp));
+ FAIL_IF(make_addr_bxy(compiler, &addr, dst, dstw, tmp1));
else
- FAIL_IF(make_addr_bx(compiler, &addr, dst, dstw, tmp));
+ FAIL_IF(make_addr_bx(compiler, &addr, dst, dstw, tmp1));
if (is_32bit)
ins = WHEN(is_u12(addr.offset), src, st, sty, addr);
@@ -1132,6 +1010,358 @@ static sljit_s32 store_word(struct sljit_compiler *compiler, sljit_gpr src,
#undef WHEN
+static sljit_s32 emit_move(struct sljit_compiler *compiler,
+ sljit_gpr dst_r,
+ sljit_s32 src, sljit_sw srcw)
+{
+ SLJIT_ASSERT(!SLOW_IS_REG(src) || dst_r != gpr(src & REG_MASK));
+
+ 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_I32_OP) != 0);
+
+ sljit_gpr src_r = gpr(src & REG_MASK);
+ return push_inst(compiler, (compiler->mode & SLJIT_I32_OP) ? lr(dst_r, src_r) : lgr(dst_r, src_r));
+}
+
+static sljit_s32 emit_rr(struct sljit_compiler *compiler, sljit_ins ins,
+ sljit_s32 dst,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
+{
+ sljit_gpr dst_r = tmp0;
+ sljit_gpr src_r = tmp1;
+ sljit_s32 needs_move = 1;
+
+ if (SLOW_IS_REG(dst)) {
+ dst_r = gpr(dst & REG_MASK);
+
+ if (dst == src1)
+ needs_move = 0;
+ else if (dst == src2) {
+ dst_r = tmp0;
+ needs_move = 2;
+ }
+ }
+
+ if (needs_move)
+ FAIL_IF(emit_move(compiler, dst_r, src1, src1w));
+
+ if (FAST_IS_REG(src2))
+ src_r = gpr(src2 & REG_MASK);
+ else
+ FAIL_IF(emit_move(compiler, tmp1, src2, src2w));
+
+ FAIL_IF(push_inst(compiler, ins | (dst_r << 4) | src_r));
+
+ if (needs_move != 2)
+ return SLJIT_SUCCESS;
+
+ dst_r = gpr(dst & REG_MASK);
+ return push_inst(compiler, (compiler->mode & SLJIT_I32_OP) ? lr(dst_r, tmp0) : lgr(dst_r, tmp0));
+}
+
+static sljit_s32 emit_rrf(struct sljit_compiler *compiler, sljit_ins ins,
+ sljit_s32 dst,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
+{
+ sljit_gpr dst_r = SLOW_IS_REG(dst) ? gpr(dst & REG_MASK) : tmp0;
+ sljit_gpr src1_r = tmp0;
+ sljit_gpr src2_r = tmp1;
+
+ if (FAST_IS_REG(src1))
+ src1_r = gpr(src1 & REG_MASK);
+ else
+ FAIL_IF(emit_move(compiler, tmp0, src1, src1w));
+
+ if (FAST_IS_REG(src2))
+ src2_r = gpr(src2 & REG_MASK);
+ else
+ FAIL_IF(emit_move(compiler, tmp1, src2, src2w));
+
+ return push_inst(compiler, ins | (dst_r << 4) | src1_r | (src2_r << 12));
+}
+
+typedef enum {
+ RI_A,
+ RIL_A,
+} emit_ril_type;
+
+static sljit_s32 emit_ri(struct sljit_compiler *compiler, sljit_ins ins,
+ sljit_s32 dst,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_sw src2w,
+ emit_ril_type type)
+{
+ sljit_gpr dst_r = tmp0;
+ sljit_s32 needs_move = 1;
+
+ if (SLOW_IS_REG(dst)) {
+ dst_r = gpr(dst & REG_MASK);
+
+ if (dst == src1)
+ needs_move = 0;
+ }
+
+ if (needs_move)
+ FAIL_IF(emit_move(compiler, dst_r, src1, src1w));
+
+ if (type == RIL_A)
+ return push_inst(compiler, ins | (dst_r << 36) | (src2w & 0xffffffff));
+ return push_inst(compiler, ins | (dst_r << 20) | (src2w & 0xffff));
+}
+
+static sljit_s32 emit_rie_d(struct sljit_compiler *compiler, sljit_ins ins,
+ sljit_s32 dst,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_sw src2w)
+{
+ sljit_gpr dst_r = SLOW_IS_REG(dst) ? gpr(dst & REG_MASK) : tmp0;
+ sljit_gpr src_r = tmp0;
+
+ if (!SLOW_IS_REG(src1))
+ FAIL_IF(emit_move(compiler, tmp0, src1, src1w));
+ else
+ src_r = gpr(src1 & REG_MASK);
+
+ return push_inst(compiler, ins | (dst_r << 36) | (src_r << 32) | (src2w & 0xffff) << 16);
+}
+
+typedef enum {
+ RX_A,
+ RXY_A,
+} emit_rx_type;
+
+static sljit_s32 emit_rx(struct sljit_compiler *compiler, sljit_ins ins,
+ sljit_s32 dst,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w,
+ emit_rx_type type)
+{
+ sljit_gpr dst_r = tmp0;
+ sljit_s32 needs_move = 1;
+ sljit_gpr base, index;
+
+ SLJIT_ASSERT(src2 & SLJIT_MEM);
+
+ if (SLOW_IS_REG(dst)) {
+ dst_r = gpr(dst);
+
+ if (dst == src1)
+ needs_move = 0;
+ else if (dst == (src2 & REG_MASK) || (dst == OFFS_REG(src2))) {
+ dst_r = tmp0;
+ needs_move = 2;
+ }
+ }
+
+ if (needs_move)
+ FAIL_IF(emit_move(compiler, dst_r, src1, src1w));
+
+ base = gpr(src2 & REG_MASK);
+ index = tmp0;
+
+ if (src2 & OFFS_REG_MASK) {
+ index = gpr(OFFS_REG(src2));
+
+ if (src2w != 0) {
+ FAIL_IF(push_inst(compiler, sllg(tmp1, index, src2w & 0x3, 0)));
+ src2w = 0;
+ index = tmp1;
+ }
+ } else if ((type == RX_A && !is_u12(src2w)) || (type == RXY_A && !is_s20(src2w))) {
+ FAIL_IF(push_load_imm_inst(compiler, tmp1, src2w));
+
+ if (src2 & REG_MASK)
+ index = tmp1;
+ else
+ base = tmp1;
+ src2w = 0;
+ }
+
+ if (type == RX_A)
+ ins |= (dst_r << 20) | (index << 16) | (base << 12) | src2w;
+ else
+ ins |= (dst_r << 36) | (index << 32) | (base << 28) | disp_s20(src2w);
+
+ FAIL_IF(push_inst(compiler, ins));
+
+ if (needs_move != 2)
+ return SLJIT_SUCCESS;
+
+ dst_r = gpr(dst);
+ return push_inst(compiler, (compiler->mode & SLJIT_I32_OP) ? lr(dst_r, tmp0) : lgr(dst_r, tmp0));
+}
+
+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;
+
+ if (dst & OFFS_REG_MASK) {
+ sljit_gpr index = tmp1;
+
+ if ((dstw & 0x3) == 0)
+ index = gpr(OFFS_REG(dst));
+ else
+ FAIL_IF(push_inst(compiler, sllg(tmp1, index, dstw & 0x3, 0)));
+
+ FAIL_IF(push_inst(compiler, la(tmp1, 0, dst_r, index)));
+ dstw = 0;
+ }
+ else if (!is_s20(dstw)) {
+ FAIL_IF(push_load_imm_inst(compiler, tmp1, dstw));
+
+ if (dst & REG_MASK)
+ FAIL_IF(push_inst(compiler, la(tmp1, 0, dst_r, tmp1)));
+
+ dstw = 0;
+ }
+ else
+ dst_r = gpr(dst & REG_MASK);
+
+ return push_inst(compiler, ins | ((srcw & 0xff) << 32) | (dst_r << 28) | disp_s20(dstw));
+}
+
+struct ins_forms {
+ sljit_ins op_r;
+ sljit_ins op_gr;
+ sljit_ins op_rk;
+ sljit_ins op_grk;
+ sljit_ins op;
+ sljit_ins op_y;
+ sljit_ins op_g;
+};
+
+static sljit_s32 emit_commutative(struct sljit_compiler *compiler, const struct ins_forms *forms,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
+{
+ sljit_s32 mode = compiler->mode;
+ sljit_ins ins, ins_k;
+
+ if ((src1 | src2) & SLJIT_MEM) {
+ sljit_ins ins12, ins20;
+
+ if (mode & SLJIT_I32_OP) {
+ ins12 = forms->op;
+ ins20 = forms->op_y;
+ }
+ else {
+ ins12 = 0;
+ ins20 = forms->op_g;
+ }
+
+ if (ins12 && ins20) {
+ /* Extra instructions needed for address computation can be executed independently. */
+ if ((src2 & SLJIT_MEM) && (!(src1 & SLJIT_MEM)
+ || ((src1 & OFFS_REG_MASK) ? (src1w & 0x3) == 0 : is_s20(src1w)))) {
+ if ((src2 & OFFS_REG_MASK) || is_u12(src2w) || !is_s20(src2w))
+ return emit_rx(compiler, ins12, dst, src1, src1w, src2, src2w, RX_A);
+
+ return emit_rx(compiler, ins20, dst, src1, src1w, src2, src2w, RXY_A);
+ }
+
+ if (src1 & SLJIT_MEM) {
+ if ((src1 & OFFS_REG_MASK) || is_u12(src1w) || !is_s20(src1w))
+ return emit_rx(compiler, ins12, dst, src2, src2w, src1, src1w, RX_A);
+
+ return emit_rx(compiler, ins20, dst, src2, src2w, src1, src1w, RXY_A);
+ }
+ }
+ else if (ins12 || ins20) {
+ emit_rx_type rx_type;
+
+ if (ins12) {
+ rx_type = RX_A;
+ ins = ins12;
+ }
+ else {
+ rx_type = RXY_A;
+ ins = ins20;
+ }
+
+ if ((src2 & SLJIT_MEM) && (!(src1 & SLJIT_MEM)
+ || ((src1 & OFFS_REG_MASK) ? (src1w & 0x3) == 0 : (rx_type == RX_A ? is_u12(src1w) : is_s20(src1w)))))
+ return emit_rx(compiler, ins, dst, src1, src1w, src2, src2w, rx_type);
+
+ if (src1 & SLJIT_MEM)
+ return emit_rx(compiler, ins, dst, src2, src2w, src1, src1w, rx_type);
+ }
+ }
+
+ if (mode & SLJIT_I32_OP) {
+ ins = forms->op_r;
+ ins_k = forms->op_rk;
+ }
+ else {
+ ins = forms->op_gr;
+ ins_k = forms->op_grk;
+ }
+
+ SLJIT_ASSERT(ins != 0 || ins_k != 0);
+
+ if (ins && SLOW_IS_REG(dst)) {
+ if (dst == src1)
+ return emit_rr(compiler, ins, dst, src1, src1w, src2, src2w);
+
+ if (dst == src2)
+ return emit_rr(compiler, ins, dst, src2, src2w, src1, src1w);
+ }
+
+ if (ins_k == 0)
+ return emit_rr(compiler, ins, dst, src1, src1w, src2, src2w);
+
+ return emit_rrf(compiler, ins_k, dst, src1, src1w, src2, src2w);
+}
+
+static sljit_s32 emit_non_commutative(struct sljit_compiler *compiler, const struct ins_forms *forms,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
+{
+ sljit_s32 mode = compiler->mode;
+ sljit_ins ins;
+
+ if (src2 & SLJIT_MEM) {
+ sljit_ins ins12, ins20;
+
+ if (mode & SLJIT_I32_OP) {
+ ins12 = forms->op;
+ ins20 = forms->op_y;
+ }
+ else {
+ ins12 = 0;
+ ins20 = forms->op_g;
+ }
+
+ if (ins12 && ins20) {
+ if ((src2 & OFFS_REG_MASK) || is_u12(src2w) || !is_s20(src2w))
+ return emit_rx(compiler, ins12, dst, src1, src1w, src2, src2w, RX_A);
+
+ return emit_rx(compiler, ins20, dst, src1, src1w, src2, src2w, RXY_A);
+ }
+ else if (ins12)
+ return emit_rx(compiler, ins12, dst, src1, src1w, src2, src2w, RX_A);
+ else if (ins20)
+ return emit_rx(compiler, ins20, dst, src1, src1w, src2, src2w, RXY_A);
+ }
+
+ ins = (mode & SLJIT_I32_OP) ? forms->op_rk : forms->op_grk;
+
+ if (ins == 0 || (SLOW_IS_REG(dst) && dst == src1))
+ return emit_rr(compiler, (mode & SLJIT_I32_OP) ? forms->op_r : forms->op_gr, dst, src1, src1w, src2, src2w);
+
+ return emit_rrf(compiler, ins, dst, src1, src1w, src2, src2w);
+}
+
SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler)
{
struct sljit_label *label;
@@ -1465,7 +1695,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compile
op = GET_OPCODE(op) | (op & SLJIT_I32_OP);
switch (op) {
case SLJIT_BREAKPOINT:
- /* TODO(mundaym): insert real breakpoint? */
+ /* The following invalid instruction is emitted by gdb. */
+ return push_inst(compiler, 0x0001 /* 2-byte trap */);
case SLJIT_NOP:
return push_inst(compiler, 0x0700 /* 2-byte nop */);
case SLJIT_LMUL_UW:
@@ -1559,6 +1790,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
/* TODO(carenas): implement prefetch? */
return SLJIT_SUCCESS;
}
+
if (opcode >= SLJIT_MOV && opcode <= SLJIT_MOV_P) {
/* LOAD REGISTER */
if (FAST_IS_REG(dst) && FAST_IS_REG(src)) {
@@ -1609,11 +1841,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
SLJIT_UNREACHABLE();
}
FAIL_IF(push_inst(compiler, ins));
- if (HAS_FLAGS(op)) {
- /* only handle zero flag */
- SLJIT_ASSERT(!(op & VARIABLE_FLAG_MASK));
- return push_store_zero_flag(compiler, op, dst_r);
- }
return SLJIT_SUCCESS;
}
/* LOAD IMMEDIATE */
@@ -1690,11 +1917,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
SLJIT_UNREACHABLE();
}
FAIL_IF(push_inst(compiler, ins));
- if (HAS_FLAGS(op)) {
- /* only handle zero flag */
- SLJIT_ASSERT(!(op & VARIABLE_FLAG_MASK));
- return push_store_zero_flag(compiler, op, reg);
- }
return SLJIT_SUCCESS;
}
/* STORE and STORE IMMEDIATE */
@@ -1723,11 +1945,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
case SLJIT_MOV_P:
case SLJIT_MOV:
FAIL_IF(push_inst(compiler, LEVAL(stg)));
- if (HAS_FLAGS(op)) {
- /* only handle zero flag */
- SLJIT_ASSERT(!(op & VARIABLE_FLAG_MASK));
- return push_store_zero_flag(compiler, op, reg);
- }
return SLJIT_SUCCESS;
default:
SLJIT_UNREACHABLE();
@@ -1767,11 +1984,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
FAIL_IF(make_addr_bxy(compiler, &mem, dst, dstw, tmp1));
FAIL_IF(push_inst(compiler,
EVAL(stg, tmp0, mem)));
- if (HAS_FLAGS(op)) {
- /* only handle zero flag */
- SLJIT_ASSERT(!(op & VARIABLE_FLAG_MASK));
- return push_store_zero_flag(compiler, op, tmp0);
- }
return SLJIT_SUCCESS;
default:
SLJIT_UNREACHABLE();
@@ -1785,7 +1997,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
dst_r = SLOW_IS_REG(dst) ? gpr(REG_MASK & dst) : tmp0;
src_r = FAST_IS_REG(src) ? gpr(REG_MASK & src) : tmp0;
if (src & SLJIT_MEM)
- FAIL_IF(load_word(compiler, src_r, src, srcw, tmp1, src & SLJIT_I32_OP));
+ FAIL_IF(load_word(compiler, src_r, src, srcw, src & SLJIT_I32_OP));
+
+ compiler->status_flags_state = op & (VARIABLE_FLAG_MASK | SLJIT_SET_Z);
/* TODO(mundaym): optimize loads and stores */
switch (opcode | (op & SLJIT_I32_OP)) {
@@ -1810,9 +2024,11 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
}
break;
case SLJIT_NEG:
+ compiler->status_flags_state |= SLJIT_CURRENT_FLAGS_ADD_SUB;
FAIL_IF(push_inst(compiler, lcgr(dst_r, src_r)));
break;
case SLJIT_NEG32:
+ compiler->status_flags_state |= SLJIT_CURRENT_FLAGS_ADD_SUB;
FAIL_IF(push_inst(compiler, lcr(dst_r, src_r)));
break;
case SLJIT_CLZ:
@@ -1839,17 +2055,12 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
SLJIT_UNREACHABLE();
}
- /* write condition code to emulated flag register */
- if (op & VARIABLE_FLAG_MASK)
- FAIL_IF(push_inst(compiler, ipm(flag_r)));
-
- /* write zero flag to emulated flag register */
- if (op & SLJIT_SET_Z)
- FAIL_IF(push_store_zero_flag(compiler, op, dst_r));
+ if ((op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK)) == (SLJIT_SET_Z | SLJIT_SET_OVERFLOW))
+ FAIL_IF(update_zero_overflow(compiler, op, dst_r));
/* TODO(carenas): doesn't need FAIL_IF */
if ((dst != SLJIT_UNUSED) && (dst & SLJIT_MEM))
- FAIL_IF(store_word(compiler, dst_r, dst, dstw, tmp1, op & SLJIT_I32_OP));
+ FAIL_IF(store_word(compiler, dst_r, dst, dstw, op & SLJIT_I32_OP));
return SLJIT_SUCCESS;
}
@@ -1887,530 +2098,554 @@ static SLJIT_INLINE int sets_signed_flag(sljit_s32 op)
return 0;
}
-/* Report whether we have an instruction for:
- op dst src imm
- where dst and src are separate registers. */
-static int have_op_3_imm(sljit_s32 op, sljit_sw imm) {
- return 0; /* TODO(mundaym): implement */
-}
-
-/* Report whether we have an instruction for:
- op reg imm
- where reg is both a source and the destination. */
-static int have_op_2_imm(sljit_s32 op, sljit_sw imm) {
- switch (GET_OPCODE(op) | (op & SLJIT_I32_OP)) {
- case SLJIT_ADD32:
- case SLJIT_ADD:
- if (!HAS_FLAGS(op) || sets_signed_flag(op))
- return have_eimm() ? is_s32(imm) : is_s16(imm);
+static const struct ins_forms add_forms = {
+ 0x1a00, /* ar */
+ 0xb9080000, /* agr */
+ 0xb9f80000, /* ark */
+ 0xb9e80000, /* agrk */
+ 0x5a000000, /* a */
+ 0xe3000000005a, /* ay */
+ 0xe30000000008, /* ag */
+};
- return have_eimm() && is_u32(imm);
- case SLJIT_MUL32:
- case SLJIT_MUL:
- /* TODO(mundaym): general extension check */
- /* for ms{,g}fi */
- if (op & VARIABLE_FLAG_MASK)
- return 0;
-
- return have_genext() && is_s16(imm);
- case SLJIT_OR32:
- case SLJIT_XOR32:
- case SLJIT_AND32:
- /* only use if have extended immediate facility */
- /* this ensures flags are set correctly */
- return have_eimm();
- case SLJIT_AND:
- case SLJIT_OR:
- case SLJIT_XOR:
- /* TODO(mundaym): make this more flexible */
- /* avoid using immediate variations, flags */
- /* won't be set correctly */
- return 0;
- case SLJIT_ADDC32:
- case SLJIT_ADDC:
- /* no ADD LOGICAL WITH CARRY IMMEDIATE */
- return 0;
- case SLJIT_SUB:
- case SLJIT_SUB32:
- case SLJIT_SUBC:
- case SLJIT_SUBC32:
- /* no SUBTRACT IMMEDIATE */
- /* TODO(mundaym): SUBTRACT LOGICAL IMMEDIATE */
- return 0;
- }
- return 0;
-}
+static const struct ins_forms logical_add_forms = {
+ 0x1e00, /* alr */
+ 0xb90a0000, /* algr */
+ 0xb9fa0000, /* alrk */
+ 0xb9ea0000, /* algrk */
+ 0x5e000000, /* al */
+ 0xe3000000005e, /* aly */
+ 0xe3000000000a, /* alg */
+};
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op,
+static sljit_s32 sljit_emit_add(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)
{
- CHECK_ERROR();
- CHECK(check_sljit_emit_op2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
- ADJUST_LOCAL_OFFSET(dst, dstw);
- ADJUST_LOCAL_OFFSET(src1, src1w);
- ADJUST_LOCAL_OFFSET(src2, src2w);
-
- if (dst == SLJIT_UNUSED && !HAS_FLAGS(op))
- return SLJIT_SUCCESS;
-
- sljit_gpr dst_r = SLOW_IS_REG(dst) ? gpr(dst & REG_MASK) : tmp0;
+ int sets_overflow = (op & VARIABLE_FLAG_MASK) == SLJIT_SET_OVERFLOW;
+ int sets_zero_overflow = (op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK)) == (SLJIT_SET_Z | SLJIT_SET_OVERFLOW);
+ const struct ins_forms *forms;
+ sljit_ins ins;
- if (is_commutative(op)) {
- #define SWAP_ARGS \
- do { \
- sljit_s32 t = src1; \
- sljit_sw tw = src1w; \
- src1 = src2; \
- src1w = src2w; \
- src2 = t; \
- src2w = tw; \
- } while(0);
-
- /* prefer immediate in src2 */
- if (src1 & SLJIT_IMM) {
- SWAP_ARGS
+ if (src2 & SLJIT_IMM) {
+ if (!sets_zero_overflow && is_s8(src2w) && (src1 & SLJIT_MEM) && (dst == src1 && dstw == src1w)) {
+ if (sets_overflow)
+ ins = (op & SLJIT_I32_OP) ? 0xeb000000006a /* asi */ : 0xeb000000007a /* agsi */;
+ else
+ ins = (op & SLJIT_I32_OP) ? 0xeb000000006e /* alsi */ : 0xeb000000007e /* algsi */;
+ return emit_siy(compiler, ins, dst, dstw, src2w);
}
- /* prefer to have src1 use same register as dst */
- if (FAST_IS_REG(src2) && gpr(src2 & REG_MASK) == dst_r) {
- SWAP_ARGS
+ if (is_s16(src2w)) {
+ if (sets_overflow)
+ ins = (op & SLJIT_I32_OP) ? 0xec00000000d8 /* ahik */ : 0xec00000000d9 /* aghik */;
+ else
+ ins = (op & SLJIT_I32_OP) ? 0xec00000000da /* alhsik */ : 0xec00000000db /* alghsik */;
+ FAIL_IF(emit_rie_d(compiler, ins, dst, src1, src1w, src2w));
+ goto done;
}
- /* prefer memory argument in src2 */
- if (FAST_IS_REG(src2) && (src1 & SLJIT_MEM)) {
- SWAP_ARGS
+ if (!sets_overflow) {
+ if ((op & SLJIT_I32_OP) || is_u32(src2w)) {
+ ins = (op & SLJIT_I32_OP) ? 0xc20b00000000 /* alfi */ : 0xc20a00000000 /* algfi */;
+ FAIL_IF(emit_ri(compiler, ins, dst, src1, src1w, src2w, RIL_A));
+ goto done;
+ }
+ if (is_u32(-src2w)) {
+ FAIL_IF(emit_ri(compiler, 0xc20400000000 /* slgfi */, dst, src1, src1w, -src2w, RIL_A));
+ goto done;
+ }
+ }
+ else if ((op & SLJIT_I32_OP) || is_s32(src2w)) {
+ ins = (op & SLJIT_I32_OP) ? 0xc20900000000 /* afi */ : 0xc20800000000 /* agfi */;
+ FAIL_IF(emit_ri(compiler, ins, dst, src1, src1w, src2w, RIL_A));
+ goto done;
}
- #undef SWAP_ARGS
}
- /* src1 must be in a register */
- sljit_gpr src1_r = FAST_IS_REG(src1) ? gpr(src1 & REG_MASK) : tmp0;
- if (src1 & SLJIT_IMM)
- FAIL_IF(push_load_imm_inst(compiler, src1_r, src1w));
-
- if (src1 & SLJIT_MEM)
- FAIL_IF(load_word(compiler, src1_r, src1, src1w, tmp1, op & SLJIT_I32_OP));
-
- /* emit comparison before subtract */
- if (GET_OPCODE(op) == SLJIT_SUB && (op & VARIABLE_FLAG_MASK)) {
- sljit_sw cmp = 0;
- switch (GET_FLAG_TYPE(op)) {
- case SLJIT_LESS:
- case SLJIT_LESS_EQUAL:
- case SLJIT_GREATER:
- case SLJIT_GREATER_EQUAL:
- cmp = 1; /* unsigned */
- break;
- case SLJIT_EQUAL:
- case SLJIT_SIG_LESS:
- case SLJIT_SIG_LESS_EQUAL:
- case SLJIT_SIG_GREATER:
- case SLJIT_SIG_GREATER_EQUAL:
- cmp = -1; /* signed */
- break;
- }
- if (cmp) {
- /* clear flags - no need to generate now */
- op &= ~VARIABLE_FLAG_MASK;
- sljit_gpr src2_r = FAST_IS_REG(src2) ? gpr(src2 & REG_MASK) : tmp1;
- if (src2 & SLJIT_IMM) {
- #define LEVAL(i) i(src1_r, src2w)
- if (cmp > 0 && is_u32(src2w)) {
- /* unsigned */
- FAIL_IF(push_inst(compiler,
- WHEN2(op & SLJIT_I32_OP, clfi, clgfi)));
- }
- else if (cmp < 0 && is_s16(src2w)) {
- /* signed */
- FAIL_IF(push_inst(compiler,
- WHEN2(op & SLJIT_I32_OP, chi, cghi)));
- }
- else if (cmp < 0 && is_s32(src2w)) {
- /* signed */
- FAIL_IF(push_inst(compiler,
- WHEN2(op & SLJIT_I32_OP, cfi, cgfi)));
- }
- #undef LEVAL
- #define LEVAL(i) i(src1_r, src2_r)
- else {
- FAIL_IF(push_load_imm_inst(compiler, src2_r, src2w));
- if (cmp > 0) {
- /* unsigned */
- FAIL_IF(push_inst(compiler,
- WHEN2(op & SLJIT_I32_OP, clr, clgr)));
- }
- if (cmp < 0) {
- /* signed */
- FAIL_IF(push_inst(compiler,
- WHEN2(op & SLJIT_I32_OP, cr, cgr)));
- }
+ forms = sets_overflow ? &add_forms : &logical_add_forms;
+ FAIL_IF(emit_commutative(compiler, forms, dst, dstw, src1, src1w, src2, src2w));
+
+done:
+ if (sets_zero_overflow)
+ FAIL_IF(update_zero_overflow(compiler, op, SLOW_IS_REG(dst) ? gpr(dst & REG_MASK) : tmp0));
+
+ if (dst & SLJIT_MEM)
+ return store_word(compiler, tmp0, dst, dstw, op & SLJIT_I32_OP);
+
+ return SLJIT_SUCCESS;
+}
+
+static const struct ins_forms sub_forms = {
+ 0x1b00, /* sr */
+ 0xb9090000, /* sgr */
+ 0xb9f90000, /* srk */
+ 0xb9e90000, /* sgrk */
+ 0x5b000000, /* s */
+ 0xe3000000005b, /* sy */
+ 0xe30000000009, /* sg */
+};
+
+static const struct ins_forms logical_sub_forms = {
+ 0x1f00, /* slr */
+ 0xb90b0000, /* slgr */
+ 0xb9fb0000, /* slrk */
+ 0xb9eb0000, /* slgrk */
+ 0x5f000000, /* sl */
+ 0xe3000000005f, /* sly */
+ 0xe3000000000b, /* slg */
+};
+
+static sljit_s32 sljit_emit_sub(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)
+{
+ int sets_signed = sets_signed_flag(op);
+ int sets_zero_overflow = (op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK)) == (SLJIT_SET_Z | SLJIT_SET_OVERFLOW);
+ const struct ins_forms *forms;
+ sljit_ins ins;
+
+ if (dst == SLJIT_UNUSED && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL) {
+ int compare_signed = GET_FLAG_TYPE(op) >= SLJIT_SIG_LESS;
+
+ compiler->status_flags_state |= SLJIT_CURRENT_FLAGS_COMPARE;
+
+ if (src2 & SLJIT_IMM) {
+ if (compare_signed || ((op & VARIABLE_FLAG_MASK) == 0 && is_s32(src2w)))
+ {
+ if ((op & SLJIT_I32_OP) || is_s32(src2w)) {
+ ins = (op & SLJIT_I32_OP) ? 0xc20d00000000 /* cfi */ : 0xc20c00000000 /* cgfi */;
+ return emit_ri(compiler, ins, src1, src1, src1w, src2w, RIL_A);
}
}
else {
- if (src2 & SLJIT_MEM) {
- /* TODO(mundaym): comparisons with memory */
- /* load src2 into register */
- FAIL_IF(load_word(compiler, src2_r, src2, src2w, tmp1, op & SLJIT_I32_OP));
+ if ((op & SLJIT_I32_OP) || is_u32(src2w)) {
+ ins = (op & SLJIT_I32_OP) ? 0xc20f00000000 /* clfi */ : 0xc20e00000000 /* clgfi */;
+ return emit_ri(compiler, ins, src1, src1, src1w, src2w, RIL_A);
}
- if (cmp > 0) {
- /* unsigned */
- FAIL_IF(push_inst(compiler,
- WHEN2(op & SLJIT_I32_OP, clr, clgr)));
- }
- if (cmp < 0) {
- /* signed */
- FAIL_IF(push_inst(compiler,
- WHEN2(op & SLJIT_I32_OP, cr, cgr)));
- }
- #undef LEVAL
+ if (is_s16(src2w))
+ return emit_rie_d(compiler, 0xec00000000db /* alghsik */, SLJIT_UNUSED, src1, src1w, src2w);
}
- FAIL_IF(push_inst(compiler, ipm(flag_r)));
}
- }
+ else if (src2 & SLJIT_MEM) {
+ if ((op & SLJIT_I32_OP) && ((src2 & OFFS_REG_MASK) || is_u12(src2w))) {
+ ins = compare_signed ? 0x59000000 /* c */ : 0x55000000 /* cl */;
+ return emit_rx(compiler, ins, src1, src1, src1w, src2, src2w, RX_A);
+ }
- if (!HAS_FLAGS(op) && dst == SLJIT_UNUSED)
- return SLJIT_SUCCESS;
+ if (compare_signed)
+ ins = (op & SLJIT_I32_OP) ? 0xe30000000059 /* cy */ : 0xe30000000020 /* cg */;
+ else
+ ins = (op & SLJIT_I32_OP) ? 0xe30000000055 /* cly */ : 0xe30000000021 /* clg */;
+ return emit_rx(compiler, ins, src1, src1, src1w, src2, src2w, RXY_A);
+ }
- /* need to specify signed or logical operation */
- int signed_flags = sets_signed_flag(op);
+ if (compare_signed)
+ ins = (op & SLJIT_I32_OP) ? 0x1900 /* cr */ : 0xb9200000 /* cgr */;
+ else
+ ins = (op & SLJIT_I32_OP) ? 0x1500 /* clr */ : 0xb9210000 /* clgr */;
+ return emit_rr(compiler, ins, src1, src1, src1w, src2, src2w);
+ }
- if (is_shift(op)) {
- /* handle shifts first, they have more constraints than other operations */
- sljit_sw d = 0;
- sljit_gpr b = FAST_IS_REG(src2) ? gpr(src2 & REG_MASK) : r0;
- if (src2 & SLJIT_IMM)
- d = src2w & ((op & SLJIT_I32_OP) ? 31 : 63);
+ if (src2 & SLJIT_IMM) {
+ sljit_sw neg_src2w = -src2w;
- if (src2 & SLJIT_MEM) {
- /* shift amount (b) cannot be in r0 (i.e. tmp0) */
- FAIL_IF(load_word(compiler, tmp1, src2, src2w, tmp1, op & SLJIT_I32_OP));
- b = tmp1;
- }
- /* src1 and dst share the same register in the base 32-bit ISA */
- /* TODO(mundaym): not needed when distinct-operand facility is available */
- int workaround_alias = op & SLJIT_I32_OP && src1_r != dst_r;
- if (workaround_alias) {
- /* put src1 into tmp0 so we can overwrite it */
- FAIL_IF(push_inst(compiler, lr(tmp0, src1_r)));
- src1_r = tmp0;
- }
- switch (GET_OPCODE(op) | (op & SLJIT_I32_OP)) {
- case SLJIT_SHL:
- FAIL_IF(push_inst(compiler, sllg(dst_r, src1_r, d, b)));
- break;
- case SLJIT_SHL32:
- FAIL_IF(push_inst(compiler, sll(src1_r, d, b)));
- break;
- case SLJIT_LSHR:
- FAIL_IF(push_inst(compiler, srlg(dst_r, src1_r, d, b)));
- break;
- case SLJIT_LSHR32:
- FAIL_IF(push_inst(compiler, srl(src1_r, d, b)));
- break;
- case SLJIT_ASHR:
- FAIL_IF(push_inst(compiler, srag(dst_r, src1_r, d, b)));
- break;
- case SLJIT_ASHR32:
- FAIL_IF(push_inst(compiler, sra(src1_r, d, b)));
- break;
- default:
- SLJIT_UNREACHABLE();
+ if (sets_signed || neg_src2w != 0 || (op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK)) == 0) {
+ if (!sets_zero_overflow && is_s8(neg_src2w) && (src1 & SLJIT_MEM) && (dst == src1 && dstw == src1w)) {
+ if (sets_signed)
+ ins = (op & SLJIT_I32_OP) ? 0xeb000000006a /* asi */ : 0xeb000000007a /* agsi */;
+ else
+ ins = (op & SLJIT_I32_OP) ? 0xeb000000006e /* alsi */ : 0xeb000000007e /* algsi */;
+ return emit_siy(compiler, ins, dst, dstw, neg_src2w);
+ }
+
+ if (is_s16(neg_src2w)) {
+ if (sets_signed)
+ ins = (op & SLJIT_I32_OP) ? 0xec00000000d8 /* ahik */ : 0xec00000000d9 /* aghik */;
+ else
+ ins = (op & SLJIT_I32_OP) ? 0xec00000000da /* alhsik */ : 0xec00000000db /* alghsik */;
+ FAIL_IF(emit_rie_d(compiler, ins, dst, src1, src1w, neg_src2w));
+ goto done;
+ }
}
- if (workaround_alias && dst_r != src1_r)
- FAIL_IF(push_inst(compiler, lr(dst_r, src1_r)));
- }
- else if ((GET_OPCODE(op) == SLJIT_MUL) && HAS_FLAGS(op)) {
- /* multiply instructions do not generally set flags so we need to manually */
- /* detect overflow conditions */
- /* TODO(mundaym): 64-bit overflow */
- SLJIT_ASSERT(GET_FLAG_TYPE(op) == SLJIT_MUL_OVERFLOW ||
- GET_FLAG_TYPE(op) == SLJIT_MUL_NOT_OVERFLOW);
- sljit_gpr src2_r = FAST_IS_REG(src2) ? gpr(src2 & REG_MASK) : tmp1;
- if (src2 & SLJIT_IMM) {
- /* load src2 into register */
- FAIL_IF(push_load_imm_inst(compiler, src2_r, src2w));
+ if (!sets_signed) {
+ if ((op & SLJIT_I32_OP) || is_u32(src2w)) {
+ ins = (op & SLJIT_I32_OP) ? 0xc20500000000 /* slfi */ : 0xc20400000000 /* slgfi */;
+ FAIL_IF(emit_ri(compiler, ins, dst, src1, src1w, src2w, RIL_A));
+ goto done;
+ }
+ if (is_u32(neg_src2w)) {
+ FAIL_IF(emit_ri(compiler, 0xc20a00000000 /* algfi */, dst, src1, src1w, neg_src2w, RIL_A));
+ goto done;
+ }
}
- if (src2 & SLJIT_MEM) {
- /* load src2 into register */
- FAIL_IF(load_word(compiler, src2_r, src2, src2w, tmp1, op & SLJIT_I32_OP));
+ else if ((op & SLJIT_I32_OP) || is_s32(neg_src2w)) {
+ ins = (op & SLJIT_I32_OP) ? 0xc20900000000 /* afi */ : 0xc20800000000 /* agfi */;
+ FAIL_IF(emit_ri(compiler, ins, dst, src1, src1w, neg_src2w, RIL_A));
+ goto done;
}
- if (have_misc2()) {
- #define LEVAL(i) i(dst_r, src1_r, src2_r)
- FAIL_IF(push_inst(compiler,
- WHEN2(op & SLJIT_I32_OP, msrkc, msgrkc)));
- #undef LEVAL
+ }
+
+ forms = sets_signed ? &sub_forms : &logical_sub_forms;
+ FAIL_IF(emit_non_commutative(compiler, forms, dst, dstw, src1, src1w, src2, src2w));
+
+done:
+ if (sets_signed) {
+ sljit_gpr dst_r = SLOW_IS_REG(dst) ? gpr(dst & REG_MASK) : tmp0;
+
+ if ((op & VARIABLE_FLAG_MASK) != SLJIT_SET_OVERFLOW) {
+ /* In case of overflow, the sign bit of the two source operands must be different, and
+ - the first operand is greater if the sign bit of the result is set
+ - the first operand is less if the sign bit of the result is not set
+ The -result operation sets the corrent sign, because the result cannot be zero.
+ The overflow is considered greater, since the result must be equal to INT_MIN so its sign bit is set. */
+ FAIL_IF(push_inst(compiler, brc(0xe, 2 + 2)));
+ FAIL_IF(push_inst(compiler, (op & SLJIT_I32_OP) ? lcr(tmp1, dst_r) : lcgr(tmp1, dst_r)));
}
- else if (op & SLJIT_I32_OP) {
- op &= ~VARIABLE_FLAG_MASK;
- FAIL_IF(push_inst(compiler, lgfr(tmp0, src1_r)));
- FAIL_IF(push_inst(compiler, msgfr(tmp0, src2_r)));
- if (dst_r != tmp0) {
- FAIL_IF(push_inst(compiler, lr(dst_r, tmp0)));
- }
- FAIL_IF(push_inst(compiler, aih(tmp0, 1)));
- FAIL_IF(push_inst(compiler, nihf(tmp0, ~1U)));
- FAIL_IF(push_inst(compiler, ipm(flag_r)));
- FAIL_IF(push_inst(compiler, oilh(flag_r, 0x2000)));
+ else if (op & SLJIT_SET_Z)
+ FAIL_IF(update_zero_overflow(compiler, op, dst_r));
+ }
+
+ if (dst & SLJIT_MEM)
+ return store_word(compiler, tmp0, dst, dstw, op & SLJIT_I32_OP);
+
+ return SLJIT_SUCCESS;
+}
+
+static const struct ins_forms multiply_forms = {
+ 0xb2520000, /* msr */
+ 0xb90c0000, /* msgr */
+ 0xb9fd0000, /* msrkc */
+ 0xb9ed0000, /* msgrkc */
+ 0x71000000, /* ms */
+ 0xe30000000051, /* msy */
+ 0xe3000000000c, /* msg */
+};
+
+static const struct ins_forms multiply_overflow_forms = {
+ 0,
+ 0,
+ 0xb9fd0000, /* msrkc */
+ 0xb9ed0000, /* msgrkc */
+ 0,
+ 0xe30000000053, /* msc */
+ 0xe30000000083, /* msgc */
+};
+
+static sljit_s32 sljit_emit_multiply(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_ins ins;
+
+ if (HAS_FLAGS(op)) {
+ /* if have_misc2 fails, this operation should be emulated. 32 bit emulation:
+ FAIL_IF(push_inst(compiler, lgfr(tmp0, src1_r)));
+ FAIL_IF(push_inst(compiler, msgfr(tmp0, src2_r)));
+ if (dst_r != tmp0) {
+ FAIL_IF(push_inst(compiler, lr(dst_r, tmp0)));
}
- else
- return SLJIT_ERR_UNSUPPORTED;
+ FAIL_IF(push_inst(compiler, aih(tmp0, 1)));
+ FAIL_IF(push_inst(compiler, nihf(tmp0, ~1U)));
+ FAIL_IF(push_inst(compiler, ipm(flag_r)));
+ FAIL_IF(push_inst(compiler, oilh(flag_r, 0x2000))); */
+ return emit_commutative(compiler, &multiply_overflow_forms, dst, dstw, src1, src1w, src2, src2w);
}
- else if ((GET_OPCODE(op) == SLJIT_SUB) && (op & SLJIT_SET_Z) && !signed_flags) {
- /* subtract logical instructions do not set the right flags unfortunately */
- /* instead, negate src2 and issue an add logical */
- /* TODO(mundaym): distinct operand facility where needed */
- if (src1_r != dst_r && src1_r != tmp0) {
- #define LEVAL(i) i(tmp0, src1_r)
- FAIL_IF(push_inst(compiler,
- WHEN2(op & SLJIT_I32_OP, lr, lgr)));
- src1_r = tmp0;
- #undef LEVAL
- }
- sljit_gpr src2_r = FAST_IS_REG(src2) ? gpr(src2 & REG_MASK) : tmp1;
- if (src2 & SLJIT_IMM) {
- /* load src2 into register */
- FAIL_IF(push_load_imm_inst(compiler, src2_r, src2w));
+
+ if (src2 & SLJIT_IMM) {
+ if (is_s16(src2w)) {
+ ins = (op & SLJIT_I32_OP) ? 0xa70c0000 /* mhi */ : 0xa70d0000 /* mghi */;
+ return emit_ri(compiler, ins, dst, src1, src1w, src2w, RI_A);
}
- if (src2 & SLJIT_MEM) {
- /* load src2 into register */
- FAIL_IF(load_word(compiler, src2_r, src2, src2w, tmp1, op & SLJIT_I32_OP));
+
+ if (is_s32(src2w)) {
+ ins = (op & SLJIT_I32_OP) ? 0xc20100000000 /* msfi */ : 0xc20000000000 /* msgfi */;
+ return emit_ri(compiler, ins, dst, src1, src1w, src2w, RIL_A);
}
- if (op & SLJIT_I32_OP) {
- FAIL_IF(push_inst(compiler, lcr(tmp1, src2_r)));
- FAIL_IF(push_inst(compiler, alr(src1_r, tmp1)));
- if (src1_r != dst_r)
- FAIL_IF(push_inst(compiler, lr(dst_r, src1_r)));
+ }
+
+ return emit_commutative(compiler, &multiply_forms, dst, dstw, src1, src1w, src2, src2w);
+}
+
+static sljit_s32 sljit_emit_bitwise_imm(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_uw imm, sljit_s32 count16)
+{
+ sljit_s32 mode = compiler->mode;
+ sljit_gpr dst_r = tmp0;
+ sljit_s32 needs_move = 1;
+
+ if (SLOW_IS_REG(dst)) {
+ dst_r = gpr(dst & REG_MASK);
+ if (dst == src1)
+ needs_move = 0;
+ }
+
+ if (needs_move)
+ FAIL_IF(emit_move(compiler, dst_r, src1, src1w));
+
+ if (type == SLJIT_AND) {
+ if (!(mode & SLJIT_I32_OP))
+ FAIL_IF(push_inst(compiler, 0xc00a00000000 /* nihf */ | (dst_r << 36) | (imm >> 32)));
+ return push_inst(compiler, 0xc00b00000000 /* nilf */ | (dst_r << 36) | (imm & 0xffffffff));
+ }
+ else if (type == SLJIT_OR) {
+ if (count16 >= 3) {
+ FAIL_IF(push_inst(compiler, 0xc00c00000000 /* oihf */ | (dst_r << 36) | (imm >> 32)));
+ return push_inst(compiler, 0xc00d00000000 /* oilf */ | (dst_r << 36) | (imm & 0xffffffff));
}
- else {
- FAIL_IF(push_inst(compiler, lcgr(tmp1, src2_r)));
- FAIL_IF(push_inst(compiler, algr(src1_r, tmp1)));
- if (src1_r != dst_r)
- FAIL_IF(push_inst(compiler, lgr(dst_r, src1_r)));
+
+ if (count16 >= 2) {
+ if ((imm & 0x00000000ffffffffull) == 0)
+ return push_inst(compiler, 0xc00c00000000 /* oihf */ | (dst_r << 36) | (imm >> 32));
+ if ((imm & 0xffffffff00000000ull) == 0)
+ return push_inst(compiler, 0xc00d00000000 /* oilf */ | (dst_r << 36) | (imm & 0xffffffff));
}
+
+ if ((imm & 0xffff000000000000ull) != 0)
+ FAIL_IF(push_inst(compiler, 0xa5080000 /* oihh */ | (dst_r << 20) | (imm >> 48)));
+ if ((imm & 0x0000ffff00000000ull) != 0)
+ FAIL_IF(push_inst(compiler, 0xa5090000 /* oihl */ | (dst_r << 20) | ((imm >> 32) & 0xffff)));
+ if ((imm & 0x00000000ffff0000ull) != 0)
+ FAIL_IF(push_inst(compiler, 0xa50a0000 /* oilh */ | (dst_r << 20) | ((imm >> 16) & 0xffff)));
+ if ((imm & 0x000000000000ffffull) != 0 || imm == 0)
+ return push_inst(compiler, 0xa50b0000 /* oill */ | (dst_r << 20) | (imm & 0xffff));
+ return SLJIT_SUCCESS;
}
- else if ((src2 & SLJIT_IMM) && (src1_r == dst_r) && have_op_2_imm(op, src2w)) {
- switch (GET_OPCODE(op) | (op & SLJIT_I32_OP)) {
- #define LEVAL(i) i(dst_r, src2w)
- case SLJIT_ADD:
- if (!HAS_FLAGS(op) || signed_flags) {
- FAIL_IF(push_inst(compiler,
- WHEN2(is_s16(src2w), aghi, agfi)));
- }
- else
- FAIL_IF(push_inst(compiler, LEVAL(algfi)));
- break;
- case SLJIT_ADD32:
- if (!HAS_FLAGS(op) || signed_flags)
- FAIL_IF(push_inst(compiler,
- WHEN2(is_s16(src2w), ahi, afi)));
+ if ((imm & 0xffffffff00000000ull) != 0)
+ FAIL_IF(push_inst(compiler, 0xc00600000000 /* xihf */ | (dst_r << 36) | (imm >> 32)));
+ if ((imm & 0x00000000ffffffffull) != 0 || imm == 0)
+ return push_inst(compiler, 0xc00700000000 /* xilf */ | (dst_r << 36) | (imm & 0xffffffff));
+ return SLJIT_SUCCESS;
+}
+
+static const struct ins_forms bitwise_and_forms = {
+ 0x1400, /* nr */
+ 0xb9800000, /* ngr */
+ 0xb9f40000, /* nrk */
+ 0xb9e40000, /* ngrk */
+ 0x54000000, /* n */
+ 0xe30000000054, /* ny */
+ 0xe30000000080, /* ng */
+};
+
+static const struct ins_forms bitwise_or_forms = {
+ 0x1600, /* or */
+ 0xb9810000, /* ogr */
+ 0xb9f60000, /* ork */
+ 0xb9e60000, /* ogrk */
+ 0x56000000, /* o */
+ 0xe30000000056, /* oy */
+ 0xe30000000081, /* og */
+};
+
+static const struct ins_forms bitwise_xor_forms = {
+ 0x1700, /* xr */
+ 0xb9820000, /* xgr */
+ 0xb9f70000, /* xrk */
+ 0xb9e70000, /* xgrk */
+ 0x57000000, /* x */
+ 0xe30000000057, /* xy */
+ 0xe30000000082, /* xg */
+};
+
+static sljit_s32 sljit_emit_bitwise(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_s32 type = GET_OPCODE(op);
+ const struct ins_forms *forms;
+
+ if ((src2 & SLJIT_IMM) && (!(op & SLJIT_SET_Z) || (type == SLJIT_AND && dst == SLJIT_UNUSED))) {
+ sljit_s32 count16 = 0;
+ sljit_uw imm = (sljit_uw)src2w;
+
+ if (op & SLJIT_I32_OP)
+ imm &= 0xffffffffull;
+
+ if ((imm & 0x000000000000ffffull) != 0 || imm == 0)
+ count16++;
+ if ((imm & 0x00000000ffff0000ull) != 0)
+ count16++;
+ if ((imm & 0x0000ffff00000000ull) != 0)
+ count16++;
+ if ((imm & 0xffff000000000000ull) != 0)
+ count16++;
+
+ if (type == SLJIT_AND && dst == SLJIT_UNUSED && count16 == 1) {
+ sljit_gpr src_r = tmp0;
+
+ if (FAST_IS_REG(src1))
+ src_r = gpr(src1 & REG_MASK);
else
- FAIL_IF(push_inst(compiler, LEVAL(alfi)));
-
- break;
- #undef LEVAL /* TODO(carenas): move down and refactor? */
- case SLJIT_MUL:
- FAIL_IF(push_inst(compiler, mhi(dst_r, src2w)));
- break;
- case SLJIT_MUL32:
- FAIL_IF(push_inst(compiler, mghi(dst_r, src2w)));
- break;
- case SLJIT_OR32:
- FAIL_IF(push_inst(compiler, oilf(dst_r, src2w)));
- break;
- case SLJIT_XOR32:
- FAIL_IF(push_inst(compiler, xilf(dst_r, src2w)));
- break;
- case SLJIT_AND32:
- FAIL_IF(push_inst(compiler, nilf(dst_r, src2w)));
- break;
- default:
- SLJIT_UNREACHABLE();
+ FAIL_IF(emit_move(compiler, tmp0, src1, src1w));
+
+ if ((imm & 0x000000000000ffffull) != 0 || imm == 0)
+ return push_inst(compiler, 0xa7010000 | (src_r << 20) | imm);
+ if ((imm & 0x00000000ffff0000ull) != 0)
+ return push_inst(compiler, 0xa7000000 | (src_r << 20) | (imm >> 16));
+ if ((imm & 0x0000ffff00000000ull) != 0)
+ return push_inst(compiler, 0xa7030000 | (src_r << 20) | (imm >> 32));
+ return push_inst(compiler, 0xa7020000 | (src_r << 20) | (imm >> 48));
}
+
+ if (!(op & SLJIT_SET_Z))
+ return sljit_emit_bitwise_imm(compiler, type, dst, dstw, src1, src1w, imm, count16);
}
- else if ((src2 & SLJIT_IMM) && have_op_3_imm(op, src2w)) {
- abort(); /* TODO(mundaym): implement */
+
+ if (type == SLJIT_AND)
+ forms = &bitwise_and_forms;
+ else if (type == SLJIT_OR)
+ forms = &bitwise_or_forms;
+ else
+ forms = &bitwise_xor_forms;
+
+ return emit_commutative(compiler, forms, dst, dstw, src1, src1w, src2, src2w);
+}
+
+static sljit_s32 sljit_emit_shift(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_s32 type = GET_OPCODE(op);
+ sljit_gpr dst_r = SLOW_IS_REG(dst) ? gpr(dst & REG_MASK) : tmp0;
+ sljit_gpr src_r = tmp0;
+ sljit_gpr base_r = tmp0;
+ sljit_ins imm = 0;
+ sljit_ins ins;
+
+ if (FAST_IS_REG(src1))
+ src_r = gpr(src1 & REG_MASK);
+ else
+ FAIL_IF(emit_move(compiler, tmp0, src1, src1w));
+
+ if (src2 & SLJIT_IMM)
+ imm = src2w & ((op & SLJIT_I32_OP) ? 0x1f : 0x3f);
+ else if (FAST_IS_REG(src2))
+ base_r = gpr(src2 & REG_MASK);
+ else {
+ FAIL_IF(emit_move(compiler, tmp1, src2, src2w));
+ base_r = tmp1;
}
- else if ((src2 & SLJIT_MEM) && (dst_r == src1_r)) {
- /* most 32-bit instructions can only handle 12-bit immediate offsets */
- int need_u12 = !have_ldisp() &&
- (op & SLJIT_I32_OP) &&
- (GET_OPCODE(op) != SLJIT_ADDC) &&
- (GET_OPCODE(op) != SLJIT_SUBC);
- struct addr mem;
- if (need_u12)
- FAIL_IF(make_addr_bx(compiler, &mem, src2, src2w, tmp1));
+
+ if ((op & SLJIT_I32_OP) && dst_r == src_r) {
+ if (type == SLJIT_SHL)
+ ins = 0x89000000 /* sll */;
+ else if (type == SLJIT_LSHR)
+ ins = 0x88000000 /* srl */;
else
- FAIL_IF(make_addr_bxy(compiler, &mem, src2, src2w, tmp1));
-
- int can_u12 = is_u12(mem.offset) ? 1 : 0;
- sljit_ins ins = 0;
- switch (GET_OPCODE(op) | (op & SLJIT_I32_OP)) {
- /* 64-bit ops */
- #define LEVAL(i) EVAL(i, dst_r, mem)
- case SLJIT_ADD:
- ins = WHEN2(signed_flags, ag, alg);
- break;
- case SLJIT_SUB:
- ins = WHEN2(signed_flags, sg, slg);
- break;
- case SLJIT_ADDC:
- ins = LEVAL(alcg);
- break;
- case SLJIT_SUBC:
- ins = LEVAL(slbg);
- break;
- case SLJIT_MUL:
- ins = LEVAL(msg);
- break;
- case SLJIT_OR:
- ins = LEVAL(og);
- break;
- case SLJIT_XOR:
- ins = LEVAL(xg);
- break;
- case SLJIT_AND:
- ins = LEVAL(ng);
- break;
- /* 32-bit ops */
- case SLJIT_ADD32:
- if (signed_flags)
- ins = WHEN2(can_u12, a, ay);
- else
- ins = WHEN2(can_u12, al, aly);
- break;
- case SLJIT_SUB32:
- if (signed_flags)
- ins = WHEN2(can_u12, s, sy);
- else
- ins = WHEN2(can_u12, sl, sly);
- break;
- case SLJIT_ADDC32:
- ins = LEVAL(alc);
- break;
- case SLJIT_SUBC32:
- ins = LEVAL(slb);
- break;
- case SLJIT_MUL32:
- ins = WHEN2(can_u12, ms, msy);
- break;
- case SLJIT_OR32:
- ins = WHEN2(can_u12, o, oy);
- break;
- case SLJIT_XOR32:
- ins = WHEN2(can_u12, x, xy);
- break;
- case SLJIT_AND32:
- ins = WHEN2(can_u12, n, ny);
- break;
- #undef LEVAL
- default:
- SLJIT_UNREACHABLE();
- }
- FAIL_IF(push_inst(compiler, ins));
+ ins = 0x8a000000 /* sra */;
+
+ FAIL_IF(push_inst(compiler, ins | (dst_r << 20) | (base_r << 12) | imm));
}
else {
- sljit_gpr src2_r = FAST_IS_REG(src2) ? gpr(src2 & REG_MASK) : tmp1;
- if (src2 & SLJIT_IMM) {
- /* load src2 into register */
- FAIL_IF(push_load_imm_inst(compiler, src2_r, src2w));
- }
- if (src2 & SLJIT_MEM) {
- /* load src2 into register */
- FAIL_IF(load_word(compiler, src2_r, src2, src2w, tmp1, op & SLJIT_I32_OP));
- }
- /* TODO(mundaym): distinct operand facility where needed */
- #define LEVAL(i) i(tmp0, src1_r)
- if (src1_r != dst_r && src1_r != tmp0) {
- FAIL_IF(push_inst(compiler,
- WHEN2(op & SLJIT_I32_OP, lr, lgr)));
- src1_r = tmp0;
- }
- #undef LEVAL
- sljit_ins ins = 0;
- switch (GET_OPCODE(op) | (op & SLJIT_I32_OP)) {
- #define LEVAL(i) i(src1_r, src2_r)
- /* 64-bit ops */
- case SLJIT_ADD:
- ins = WHEN2(signed_flags, agr, algr);
- break;
- case SLJIT_SUB:
- ins = WHEN2(signed_flags, sgr, slgr);
- break;
- case SLJIT_ADDC:
- ins = LEVAL(alcgr);
- break;
- case SLJIT_SUBC:
- ins = LEVAL(slbgr);
- break;
- case SLJIT_MUL:
- ins = LEVAL(msgr);
- break;
- case SLJIT_AND:
- ins = LEVAL(ngr);
- break;
- case SLJIT_OR:
- ins = LEVAL(ogr);
- break;
- case SLJIT_XOR:
- ins = LEVAL(xgr);
- break;
- /* 32-bit ops */
- case SLJIT_ADD32:
- ins = WHEN2(signed_flags, ar, alr);
- break;
- case SLJIT_SUB32:
- ins = WHEN2(signed_flags, sr, slr);
- break;
- case SLJIT_ADDC32:
- ins = LEVAL(alcr);
- break;
- case SLJIT_SUBC32:
- ins = LEVAL(slbr);
- break;
- case SLJIT_MUL32:
- ins = LEVAL(msr);
- break;
- case SLJIT_AND32:
- ins = LEVAL(nr);
- break;
- case SLJIT_OR32:
- ins = LEVAL(or);
- break;
- case SLJIT_XOR32:
- ins = LEVAL(xr);
- break;
- #undef LEVAL
- default:
- SLJIT_UNREACHABLE();
- }
- FAIL_IF(push_inst(compiler, ins));
- #define LEVAL(i) i(dst_r, src1_r)
- if (src1_r != dst_r)
- FAIL_IF(push_inst(compiler,
- WHEN2(op & SLJIT_I32_OP, lr, lgr)));
- #undef LEVAL
+ if (type == SLJIT_SHL)
+ ins = (op & SLJIT_I32_OP) ? 0xeb00000000df /* sllk */ : 0xeb000000000d /* sllg */;
+ else if (type == SLJIT_LSHR)
+ ins = (op & SLJIT_I32_OP) ? 0xeb00000000de /* srlk */ : 0xeb000000000c /* srlg */;
+ else
+ ins = (op & SLJIT_I32_OP) ? 0xeb00000000dc /* srak */ : 0xeb000000000a /* srag */;
+
+ FAIL_IF(push_inst(compiler, ins | (dst_r << 36) | (src_r << 32) | (base_r << 28) | (imm << 16)));
}
- /* write condition code to emulated flag register */
- if (op & VARIABLE_FLAG_MASK)
- FAIL_IF(push_inst(compiler, ipm(flag_r)));
+ if ((op & SLJIT_SET_Z) && type != SLJIT_ASHR)
+ return push_inst(compiler, (op & SLJIT_I32_OP) ? or(dst_r, dst_r) : ogr(dst_r, dst_r));
+
+ return SLJIT_SUCCESS;
+}
+
+static const struct ins_forms addc_forms = {
+ 0xb9980000, /* alcr */
+ 0xb9880000, /* alcgr */
+ 0,
+ 0,
+ 0,
+ 0xe30000000098, /* alc */
+ 0xe30000000088, /* alcg */
+};
+
+static const struct ins_forms subc_forms = {
+ 0xb9990000, /* slbr */
+ 0xb9890000, /* slbgr */
+ 0,
+ 0,
+ 0,
+ 0xe30000000099, /* slb */
+ 0xe30000000089, /* slbg */
+};
+
+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)
+{
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_op2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
+ ADJUST_LOCAL_OFFSET(dst, dstw);
+ ADJUST_LOCAL_OFFSET(src1, src1w);
+ ADJUST_LOCAL_OFFSET(src2, src2w);
+
+ if (dst == SLJIT_UNUSED && !HAS_FLAGS(op))
+ return SLJIT_SUCCESS;
- /* write zero flag to emulated flag register */
- if (op & SLJIT_SET_Z)
- FAIL_IF(push_store_zero_flag(compiler, op, dst_r));
+ compiler->mode = op & SLJIT_I32_OP;
+ compiler->status_flags_state = op & (VARIABLE_FLAG_MASK | SLJIT_SET_Z);
+
+ if (GET_OPCODE(op) >= SLJIT_ADD || GET_OPCODE(op) <= SLJIT_SUBC)
+ compiler->status_flags_state |= SLJIT_CURRENT_FLAGS_ADD_SUB;
+
+ if (is_commutative(op) && (src1 & SLJIT_IMM) && !(src2 & SLJIT_IMM)) {
+ src1 ^= src2;
+ src2 ^= src1;
+ src1 ^= src2;
+
+ src1w ^= src2w;
+ src2w ^= src1w;
+ src1w ^= src2w;
+ }
- /* finally write the result to memory if required */
- if (dst & SLJIT_MEM) {
- SLJIT_ASSERT(dst_r != tmp1);
- /* TODO(carenas): s/FAIL_IF/ return */
- FAIL_IF(store_word(compiler, dst_r, dst, dstw, tmp1, op & SLJIT_I32_OP));
+ switch (GET_OPCODE(op)) {
+ case SLJIT_ADD:
+ return sljit_emit_add(compiler, op, dst, dstw, src1, src1w, src2, src2w);
+ case SLJIT_ADDC:
+ FAIL_IF(emit_commutative(compiler, &addc_forms, dst, dstw, src1, src1w, src2, src2w));
+ if (dst & SLJIT_MEM)
+ return store_word(compiler, tmp0, dst, dstw, op & SLJIT_I32_OP);
+ return SLJIT_SUCCESS;
+ case SLJIT_SUB:
+ return sljit_emit_sub(compiler, op, dst, dstw, src1, src1w, src2, src2w);
+ case SLJIT_SUBC:
+ FAIL_IF(emit_non_commutative(compiler, &subc_forms, dst, dstw, src1, src1w, src2, src2w));
+ if (dst & SLJIT_MEM)
+ return store_word(compiler, tmp0, dst, dstw, op & SLJIT_I32_OP);
+ return SLJIT_SUCCESS;
+ case SLJIT_MUL:
+ FAIL_IF(sljit_emit_multiply(compiler, op, dst, dstw, src1, src1w, src2, src2w));
+ break;
+ case SLJIT_AND:
+ case SLJIT_OR:
+ case SLJIT_XOR:
+ FAIL_IF(sljit_emit_bitwise(compiler, op, dst, dstw, src1, src1w, src2, src2w));
+ break;
+ case SLJIT_SHL:
+ case SLJIT_LSHR:
+ case SLJIT_ASHR:
+ FAIL_IF(sljit_emit_shift(compiler, op, dst, dstw, src1, src1w, src2, src2w));
+ break;
}
+ if (dst & SLJIT_MEM)
+ return store_word(compiler, tmp0, dst, dstw, op & SLJIT_I32_OP);
return SLJIT_SUCCESS;
}
@@ -2428,7 +2663,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(
case SLJIT_FAST_RETURN:
src_r = FAST_IS_REG(src) ? gpr(src) : tmp1;
if (src & SLJIT_MEM)
- FAIL_IF(load_word(compiler, tmp1, src, srcw, tmp1, 0));
+ FAIL_IF(load_word(compiler, tmp1, src, srcw, 0));
return push_inst(compiler, br(src_r));
case SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN:
@@ -2507,7 +2742,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *
return push_inst(compiler, lgr(gpr(dst), fast_link_r));
/* memory */
- return store_word(compiler, fast_link_r, dst, dstw, tmp1, 0);
+ return store_word(compiler, fast_link_r, dst, dstw, 0);
}
/* --------------------------------------------------------------------- */
@@ -2532,15 +2767,11 @@ 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)
{
- sljit_u8 mask = ((type & 0xff) < SLJIT_JUMP) ? get_cc(type & 0xff) : 0xf;
+ sljit_u8 mask = ((type & 0xff) < SLJIT_JUMP) ? get_cc(compiler, type & 0xff) : 0xf;
CHECK_ERROR_PTR();
CHECK_PTR(check_sljit_emit_jump(compiler, type));
- /* reload condition code */
- if (mask != 0xf)
- PTR_FAIL_IF(push_load_cc(compiler, type & 0xff));
-
/* record jump */
struct sljit_jump *jump = (struct sljit_jump *)
ensure_abuf(compiler, sizeof(struct sljit_jump));
@@ -2585,7 +2816,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi
FAIL_IF(push_load_imm_inst(compiler, src_r, srcw));
}
else if (src & SLJIT_MEM)
- FAIL_IF(load_word(compiler, src_r, src, srcw, tmp1, 0 /* 64-bit */));
+ FAIL_IF(load_word(compiler, src_r, src, srcw, 0 /* 64-bit */));
/* emit jump instruction */
if (type >= SLJIT_FAST_CALL)
@@ -2613,7 +2844,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
sljit_s32 dst, sljit_sw dstw,
sljit_s32 type)
{
- sljit_u8 mask = get_cc(type & 0xff);
+ sljit_u8 mask = get_cc(compiler, type & 0xff);
CHECK_ERROR();
CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, type));
@@ -2624,9 +2855,11 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
case SLJIT_AND:
case SLJIT_OR:
case SLJIT_XOR:
+ compiler->status_flags_state = op & SLJIT_SET_Z;
+
/* dst is also source operand */
if (dst & SLJIT_MEM)
- FAIL_IF(load_word(compiler, dst_r, dst, dstw, tmp1, op & SLJIT_I32_OP));
+ FAIL_IF(load_word(compiler, dst_r, dst, dstw, op & SLJIT_I32_OP));
break;
case SLJIT_MOV:
@@ -2638,9 +2871,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
SLJIT_UNREACHABLE();
}
- if (mask != 0xf)
- FAIL_IF(push_load_cc(compiler, type & 0xff));
-
/* TODO(mundaym): fold into cmov helper function? */
#define LEVAL(i) i(loc_r, 1, mask)
if (have_lscond2()) {
@@ -2671,14 +2901,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
#undef LEVAL
}
- /* set zero flag if needed */
- if (op & SLJIT_SET_Z)
- FAIL_IF(push_store_zero_flag(compiler, op, dst_r));
-
/* store result to memory if required */
- /* TODO(carenas): s/FAIL_IF/ return */
if (dst & SLJIT_MEM)
- FAIL_IF(store_word(compiler, dst_r, dst, dstw, tmp1, op & SLJIT_I32_OP));
+ return store_word(compiler, dst_r, dst, dstw, op & SLJIT_I32_OP);
return SLJIT_SUCCESS;
}
@@ -2687,16 +2912,13 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compil
sljit_s32 dst_reg,
sljit_s32 src, sljit_sw srcw)
{
- sljit_u8 mask = get_cc(type & 0xff);
+ sljit_u8 mask = get_cc(compiler, type & 0xff);
sljit_gpr dst_r = gpr(dst_reg & ~SLJIT_I32_OP);
sljit_gpr src_r = FAST_IS_REG(src) ? gpr(src) : tmp0;
CHECK_ERROR();
CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw));
- if (mask != 0xf)
- FAIL_IF(push_load_cc(compiler, type & 0xff));
-
if (src & SLJIT_IMM) {
/* TODO(mundaym): fast path with lscond2 */
FAIL_IF(push_load_imm_inst(compiler, src_r, srcw));
@@ -2750,7 +2972,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi
}
if (dst & SLJIT_MEM)
- PTR_FAIL_IF(store_word(compiler, dst_r, dst, dstw, tmp1, 0 /* always 64-bit */));
+ PTR_FAIL_IF(store_word(compiler, dst_r, dst, dstw, 0 /* always 64-bit */));
return (struct sljit_const*)const_;
}
@@ -2797,7 +3019,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label *sljit_emit_put_label(
}
if (dst & SLJIT_MEM)
- PTR_FAIL_IF(store_word(compiler, dst_r, dst, dstw, tmp1, 0));
+ PTR_FAIL_IF(store_word(compiler, dst_r, dst, dstw, 0));
return put_label;
}
diff --git a/thirdparty/pcre2/src/sljit/sljitNativeSPARC_32.c b/thirdparty/pcre2/src/sljit/sljitNativeSPARC_32.c
index e5167f02ba..28886405af 100644
--- a/thirdparty/pcre2/src/sljit/sljitNativeSPARC_32.c
+++ b/thirdparty/pcre2/src/sljit/sljitNativeSPARC_32.c
@@ -93,18 +93,21 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
return push_inst(compiler, ADD | D(dst) | S1(dst) | IMM(1), UNMOVABLE_INS);
case SLJIT_ADD:
+ compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD_SUB;
return push_inst(compiler, ADD | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
case SLJIT_ADDC:
return push_inst(compiler, ADDC | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
case SLJIT_SUB:
+ compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD_SUB;
return push_inst(compiler, SUB | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
case SLJIT_SUBC:
return push_inst(compiler, SUBC | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
case SLJIT_MUL:
+ compiler->status_flags_state = 0;
FAIL_IF(push_inst(compiler, SMUL | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst)));
if (!(flags & SET_FLAGS))
return SLJIT_SUCCESS;
diff --git a/thirdparty/pcre2/src/sljit/sljitNativeSPARC_common.c b/thirdparty/pcre2/src/sljit/sljitNativeSPARC_common.c
index 544d80d028..e833f09d7a 100644
--- a/thirdparty/pcre2/src/sljit/sljitNativeSPARC_common.c
+++ b/thirdparty/pcre2/src/sljit/sljitNativeSPARC_common.c
@@ -1275,16 +1275,14 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compi
return label;
}
-static sljit_ins get_cc(sljit_s32 type)
+static sljit_ins get_cc(struct sljit_compiler *compiler, sljit_s32 type)
{
switch (type) {
case SLJIT_EQUAL:
- case SLJIT_MUL_NOT_OVERFLOW:
case SLJIT_NOT_EQUAL_F64: /* Unordered. */
return DA(0x1);
case SLJIT_NOT_EQUAL:
- case SLJIT_MUL_OVERFLOW:
case SLJIT_EQUAL_F64:
return DA(0x9);
@@ -1317,10 +1315,16 @@ static sljit_ins get_cc(sljit_s32 type)
return DA(0x2);
case SLJIT_OVERFLOW:
+ if (!(compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD_SUB))
+ return DA(0x9);
+
case SLJIT_UNORDERED_F64:
return DA(0x7);
case SLJIT_NOT_OVERFLOW:
+ if (!(compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD_SUB))
+ return DA(0x1);
+
case SLJIT_ORDERED_F64:
return DA(0xf);
@@ -1347,7 +1351,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
if (((compiler->delay_slot & DST_INS_MASK) != UNMOVABLE_INS) && !(compiler->delay_slot & ICC_IS_SET))
jump->flags |= IS_MOVABLE;
#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
- PTR_FAIL_IF(push_inst(compiler, BICC | get_cc(type ^ 1) | 5, UNMOVABLE_INS));
+ PTR_FAIL_IF(push_inst(compiler, BICC | get_cc(compiler, type ^ 1) | 5, UNMOVABLE_INS));
#else
#error "Implementation required"
#endif
@@ -1357,7 +1361,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
if (((compiler->delay_slot & DST_INS_MASK) != UNMOVABLE_INS) && !(compiler->delay_slot & FCC_IS_SET))
jump->flags |= IS_MOVABLE;
#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
- PTR_FAIL_IF(push_inst(compiler, FBFCC | get_cc(type ^ 1) | 5, UNMOVABLE_INS));
+ PTR_FAIL_IF(push_inst(compiler, FBFCC | get_cc(compiler, type ^ 1) | 5, UNMOVABLE_INS));
#else
#error "Implementation required"
#endif
@@ -1474,9 +1478,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
type &= 0xff;
if (type < SLJIT_EQUAL_F64)
- FAIL_IF(push_inst(compiler, BICC | get_cc(type) | 3, UNMOVABLE_INS));
+ FAIL_IF(push_inst(compiler, BICC | get_cc(compiler, type) | 3, UNMOVABLE_INS));
else
- FAIL_IF(push_inst(compiler, FBFCC | get_cc(type) | 3, UNMOVABLE_INS));
+ FAIL_IF(push_inst(compiler, FBFCC | get_cc(compiler, type) | 3, UNMOVABLE_INS));
FAIL_IF(push_inst(compiler, OR | D(reg) | S1(0) | IMM(1), UNMOVABLE_INS));
FAIL_IF(push_inst(compiler, OR | D(reg) | S1(0) | IMM(0), UNMOVABLE_INS));
diff --git a/thirdparty/pcre2/src/sljit/sljitNativeX86_common.c b/thirdparty/pcre2/src/sljit/sljitNativeX86_common.c
index ddcc5ebf76..515d98aefd 100644
--- a/thirdparty/pcre2/src/sljit/sljitNativeX86_common.c
+++ b/thirdparty/pcre2/src/sljit/sljitNativeX86_common.c
@@ -411,11 +411,9 @@ static sljit_u8 get_jump_code(sljit_s32 type)
return 0x8e /* jle */;
case SLJIT_OVERFLOW:
- case SLJIT_MUL_OVERFLOW:
return 0x80 /* jo */;
case SLJIT_NOT_OVERFLOW:
- case SLJIT_MUL_NOT_OVERFLOW:
return 0x81 /* jno */;
case SLJIT_UNORDERED_F64:
diff --git a/thirdparty/pcre2/src/sljit/sljitUtils.c b/thirdparty/pcre2/src/sljit/sljitUtils.c
index 08ca35cf37..9bce714735 100644
--- a/thirdparty/pcre2/src/sljit/sljitUtils.c
+++ b/thirdparty/pcre2/src/sljit/sljitUtils.c
@@ -48,7 +48,7 @@ static HANDLE allocator_lock;
static SLJIT_INLINE void allocator_grab_lock(void)
{
HANDLE lock;
- if (SLJIT_UNLIKELY(!allocator_lock)) {
+ if (SLJIT_UNLIKELY(!InterlockedCompareExchangePointer(&allocator_lock, NULL, NULL))) {
lock = CreateMutex(NULL, FALSE, NULL);
if (InterlockedCompareExchangePointer(&allocator_lock, lock, NULL))
CloseHandle(lock);
@@ -146,9 +146,13 @@ static SLJIT_INLINE sljit_sw get_page_alignment(void) {
#include <unistd.h>
static SLJIT_INLINE sljit_sw get_page_alignment(void) {
- static sljit_sw sljit_page_align;
- if (!sljit_page_align) {
+ static sljit_sw sljit_page_align = -1;
+ if (sljit_page_align < 0) {
+#ifdef _SC_PAGESIZE
sljit_page_align = sysconf(_SC_PAGESIZE);
+#else
+ sljit_page_align = getpagesize();
+#endif
/* Should never happen. */
if (sljit_page_align < 0)
sljit_page_align = 4096;
diff --git a/thirdparty/pcre2/src/sljit/sljitWXExecAllocator.c b/thirdparty/pcre2/src/sljit/sljitWXExecAllocator.c
index 6ef71f7d83..72d5b8dd2b 100644
--- a/thirdparty/pcre2/src/sljit/sljitWXExecAllocator.c
+++ b/thirdparty/pcre2/src/sljit/sljitWXExecAllocator.c
@@ -121,14 +121,18 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
static pthread_mutex_t se_lock = PTHREAD_MUTEX_INITIALIZER;
#endif
static int se_protected = !SLJIT_PROT_WX;
+ int prot = PROT_READ | PROT_WRITE | SLJIT_PROT_WX;
sljit_uw* ptr;
if (SLJIT_UNLIKELY(se_protected < 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_READ | PROT_WRITE | SLJIT_PROT_WX,
- MAP_PRIVATE | MAP_ANON, -1, 0);
+ ptr = (sljit_uw*)mmap(NULL, size, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
if (ptr == MAP_FAILED)
return NULL;
diff --git a/thirdparty/tinyexr/tinyexr.cc b/thirdparty/tinyexr/tinyexr.cc
index fef8f66c98..70115ea5c2 100644
--- a/thirdparty/tinyexr/tinyexr.cc
+++ b/thirdparty/tinyexr/tinyexr.cc
@@ -4,5 +4,9 @@
#endif
#endif
+// -- GODOT start --
+#include <zlib.h> // Should come before including tinyexr.
+// -- GODOT end --
+
#define TINYEXR_IMPLEMENTATION
#include "tinyexr.h"
diff --git a/thirdparty/tinyexr/tinyexr.h b/thirdparty/tinyexr/tinyexr.h
index a3e7b23161..969f07ad79 100644
--- a/thirdparty/tinyexr/tinyexr.h
+++ b/thirdparty/tinyexr/tinyexr.h
@@ -1,7 +1,7 @@
#ifndef TINYEXR_H_
#define TINYEXR_H_
/*
-Copyright (c) 2014 - 2020, Syoyo Fujita and many contributors.
+Copyright (c) 2014 - 2021, Syoyo Fujita and many contributors.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -65,6 +65,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// End of OpenEXR license -------------------------------------------------
+
//
//
// Do this:
@@ -88,7 +89,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
extern "C" {
#endif
-// Use embedded miniz or not to decode ZIP format pixel. Linking with zlib
+#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || \
+ defined(__i386) || defined(__i486__) || defined(__i486) || \
+ defined(i386) || defined(__ia64__) || defined(__x86_64__)
+#define TINYEXR_X86_OR_X64_CPU 1
+#else
+#define TINYEXR_X86_OR_X64_CPU 0
+#endif
+
+#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || TINYEXR_X86_OR_X64_CPU
+#define TINYEXR_LITTLE_ENDIAN 1
+#else
+#define TINYEXR_LITTLE_ENDIAN 0
+#endif
+
+// Use miniz or not to decode ZIP format pixel. Linking with zlib
// required if this flas is 0.
#ifndef TINYEXR_USE_MINIZ
#define TINYEXR_USE_MINIZ (1)
@@ -162,9 +177,13 @@ extern "C" {
typedef struct _EXRVersion {
int version; // this must be 2
- int tiled; // tile format image
+ // tile format image;
+ // not zero for only a single-part "normal" tiled file (according to spec.)
+ int tiled;
int long_name; // long name attribute
- int non_image; // deep image(EXR 2.0)
+ // deep image(EXR 2.0);
+ // for a multi-part file, indicates that at least one part is of type deep* (according to spec.)
+ int non_image;
int multipart; // multi-part(EXR 2.0)
} EXRVersion;
@@ -222,6 +241,8 @@ typedef struct _EXRHeader {
int tile_rounding_mode;
int long_name;
+ // for a single-part file, agree with the version field bit 11
+ // for a multi-part file, it is consistent with the type of part
int non_image;
int multipart;
unsigned int header_len;
@@ -244,7 +265,11 @@ typedef struct _EXRHeader {
// ParseEXRHeaderFrom(Meomory|File), then users
// can edit it(only valid for HALF pixel type
// channel)
-
+ // name attribute required for multipart files;
+ // must be unique and non empty (according to spec.);
+ // use EXRSetNameAttr for setting value;
+ // max 255 character allowed - excluding terminating zero
+ char name[256];
} EXRHeader;
typedef struct _EXRMultiPartHeader {
@@ -256,6 +281,10 @@ typedef struct _EXRMultiPartHeader {
typedef struct _EXRImage {
EXRTile *tiles; // Tiled pixel data. The application must reconstruct image
// from tiles manually. NULL if scanline format.
+ struct _EXRImage* next_level; // NULL if scanline format or image is the last level.
+ int level_x; // x level index
+ int level_y; // y level index
+
unsigned char **images; // image[channels][pixels]. NULL if tiled format.
int width;
@@ -339,9 +368,15 @@ extern int SaveEXR(const float *data, const int width, const int height,
const int components, const int save_as_fp16,
const char *filename, const char **err);
+// Returns the number of resolution levels of the image (including the base)
+extern int EXRNumLevels(const EXRImage* exr_image);
+
// Initialize EXRHeader struct
extern void InitEXRHeader(EXRHeader *exr_header);
+// Set name attribute of EXRHeader struct (it makes a copy)
+extern void EXRSetNameAttr(EXRHeader *exr_header, const char* name);
+
// Initialize EXRImage struct
extern void InitEXRImage(EXRImage *exr_image);
@@ -465,6 +500,30 @@ extern size_t SaveEXRImageToMemory(const EXRImage *image,
const EXRHeader *exr_header,
unsigned char **memory, const char **err);
+// Saves multi-channel, multi-frame OpenEXR image to a memory.
+// Image is compressed using EXRImage.compression value.
+// File global attributes (eg. display_window) must be set in the first header.
+// Returns negative value and may set error string in `err` when there's an
+// error
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
+extern int SaveEXRMultipartImageToFile(const EXRImage *images,
+ const EXRHeader **exr_headers,
+ unsigned int num_parts,
+ const char *filename, const char **err);
+
+// Saves multi-channel, multi-frame OpenEXR image to a memory.
+// Image is compressed using EXRImage.compression value.
+// File global attributes (eg. display_window) must be set in the first header.
+// Return the number of bytes if success.
+// Return zero and will set error string in `err` when there's an
+// error.
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
+extern size_t SaveEXRMultipartImageToMemory(const EXRImage *images,
+ const EXRHeader **exr_headers,
+ unsigned int num_parts,
+ unsigned char **memory, const char **err);
// Loads single-frame OpenEXR deep image.
// Application must free memory of variables in DeepImage(image, offset_table)
// Returns negative value and may set error string in `err` when there's an
@@ -514,6 +573,9 @@ extern int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
#include <windows.h> // for UTF-8
#endif
@@ -530,8 +592,11 @@ extern int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
#include <limits>
#include <string>
#include <vector>
+#include <set>
-#if __cplusplus > 199711L
+// https://stackoverflow.com/questions/5047971/how-do-i-check-for-c11-support
+#if __cplusplus > 199711L || (defined(_MSC_VER) && _MSC_VER >= 1900)
+#define TINYEXR_HAS_CXX11 (1)
// C++11
#include <cstdint>
@@ -547,6 +612,7 @@ extern int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
#endif
#if TINYEXR_USE_MINIZ
+#include <miniz.h>
#else
// Issue #46. Please include your own zlib-compatible API header before
// including `tinyexr.h`
@@ -588,6467 +654,6 @@ typedef long long tinyexr_int64;
#endif
#endif
-#if TINYEXR_USE_MINIZ
-
-namespace miniz {
-
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wc++11-long-long"
-#pragma clang diagnostic ignored "-Wold-style-cast"
-#pragma clang diagnostic ignored "-Wpadded"
-#pragma clang diagnostic ignored "-Wsign-conversion"
-#pragma clang diagnostic ignored "-Wc++11-extensions"
-#pragma clang diagnostic ignored "-Wconversion"
-#pragma clang diagnostic ignored "-Wunused-function"
-#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
-#pragma clang diagnostic ignored "-Wundef"
-
-#if __has_warning("-Wcomma")
-#pragma clang diagnostic ignored "-Wcomma"
-#endif
-
-#if __has_warning("-Wmacro-redefined")
-#pragma clang diagnostic ignored "-Wmacro-redefined"
-#endif
-
-#if __has_warning("-Wcast-qual")
-#pragma clang diagnostic ignored "-Wcast-qual"
-#endif
-
-#if __has_warning("-Wzero-as-null-pointer-constant")
-#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
-#endif
-
-#if __has_warning("-Wtautological-constant-compare")
-#pragma clang diagnostic ignored "-Wtautological-constant-compare"
-#endif
-
-#if __has_warning("-Wextra-semi-stmt")
-#pragma clang diagnostic ignored "-Wextra-semi-stmt"
-#endif
-
-#endif
-
-/* miniz.c v1.15 - public domain deflate/inflate, zlib-subset, ZIP
- reading/writing/appending, PNG writing
- See "unlicense" statement at the end of this file.
- Rich Geldreich <richgel99@gmail.com>, last updated Oct. 13, 2013
- Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951:
- http://www.ietf.org/rfc/rfc1951.txt
-
- Most API's defined in miniz.c are optional. For example, to disable the
- archive related functions just define
- MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO
- (see the list below for more macros).
-
- * Change History
- 10/13/13 v1.15 r4 - Interim bugfix release while I work on the next major
- release with Zip64 support (almost there!):
- - Critical fix for the MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY bug
- (thanks kahmyong.moon@hp.com) which could cause locate files to not find
- files. This bug
- would only have occurred in earlier versions if you explicitly used this
- flag, OR if you used mz_zip_extract_archive_file_to_heap() or
- mz_zip_add_mem_to_archive_file_in_place()
- (which used this flag). If you can't switch to v1.15 but want to fix
- this bug, just remove the uses of this flag from both helper funcs (and of
- course don't use the flag).
- - Bugfix in mz_zip_reader_extract_to_mem_no_alloc() from kymoon when
- pUser_read_buf is not NULL and compressed size is > uncompressed size
- - Fixing mz_zip_reader_extract_*() funcs so they don't try to extract
- compressed data from directory entries, to account for weird zipfiles which
- contain zero-size compressed data on dir entries.
- Hopefully this fix won't cause any issues on weird zip archives,
- because it assumes the low 16-bits of zip external attributes are DOS
- attributes (which I believe they always are in practice).
- - Fixing mz_zip_reader_is_file_a_directory() so it doesn't check the
- internal attributes, just the filename and external attributes
- - mz_zip_reader_init_file() - missing MZ_FCLOSE() call if the seek failed
- - Added cmake support for Linux builds which builds all the examples,
- tested with clang v3.3 and gcc v4.6.
- - Clang fix for tdefl_write_image_to_png_file_in_memory() from toffaletti
- - Merged MZ_FORCEINLINE fix from hdeanclark
- - Fix <time.h> include before config #ifdef, thanks emil.brink
- - Added tdefl_write_image_to_png_file_in_memory_ex(): supports Y flipping
- (super useful for OpenGL apps), and explicit control over the compression
- level (so you can
- set it to 1 for real-time compression).
- - Merged in some compiler fixes from paulharris's github repro.
- - Retested this build under Windows (VS 2010, including static analysis),
- tcc 0.9.26, gcc v4.6 and clang v3.3.
- - Added example6.c, which dumps an image of the mandelbrot set to a PNG
- file.
- - Modified example2 to help test the
- MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY flag more.
- - In r3: Bugfix to mz_zip_writer_add_file() found during merge: Fix
- possible src file fclose() leak if alignment bytes+local header file write
- faiiled
- - In r4: Minor bugfix to mz_zip_writer_add_from_zip_reader():
- Was pushing the wrong central dir header offset, appears harmless in this
- release, but it became a problem in the zip64 branch
- 5/20/12 v1.14 - MinGW32/64 GCC 4.6.1 compiler fixes: added MZ_FORCEINLINE,
- #include <time.h> (thanks fermtect).
- 5/19/12 v1.13 - From jason@cornsyrup.org and kelwert@mtu.edu - Fix
- mz_crc32() so it doesn't compute the wrong CRC-32's when mz_ulong is 64-bit.
- - Temporarily/locally slammed in "typedef unsigned long mz_ulong" and
- re-ran a randomized regression test on ~500k files.
- - Eliminated a bunch of warnings when compiling with GCC 32-bit/64.
- - Ran all examples, miniz.c, and tinfl.c through MSVC 2008's /analyze
- (static analysis) option and fixed all warnings (except for the silly
- "Use of the comma-operator in a tested expression.." analysis warning,
- which I purposely use to work around a MSVC compiler warning).
- - Created 32-bit and 64-bit Codeblocks projects/workspace. Built and
- tested Linux executables. The codeblocks workspace is compatible with
- Linux+Win32/x64.
- - Added miniz_tester solution/project, which is a useful little app
- derived from LZHAM's tester app that I use as part of the regression test.
- - Ran miniz.c and tinfl.c through another series of regression testing on
- ~500,000 files and archives.
- - Modified example5.c so it purposely disables a bunch of high-level
- functionality (MINIZ_NO_STDIO, etc.). (Thanks to corysama for the
- MINIZ_NO_STDIO bug report.)
- - Fix ftell() usage in examples so they exit with an error on files which
- are too large (a limitation of the examples, not miniz itself).
- 4/12/12 v1.12 - More comments, added low-level example5.c, fixed a couple
- minor level_and_flags issues in the archive API's.
- level_and_flags can now be set to MZ_DEFAULT_COMPRESSION. Thanks to Bruce
- Dawson <bruced@valvesoftware.com> for the feedback/bug report.
- 5/28/11 v1.11 - Added statement from unlicense.org
- 5/27/11 v1.10 - Substantial compressor optimizations:
- - Level 1 is now ~4x faster than before. The L1 compressor's throughput
- now varies between 70-110MB/sec. on a
- - Core i7 (actual throughput varies depending on the type of data, and x64
- vs. x86).
- - Improved baseline L2-L9 compression perf. Also, greatly improved
- compression perf. issues on some file types.
- - Refactored the compression code for better readability and
- maintainability.
- - Added level 10 compression level (L10 has slightly better ratio than
- level 9, but could have a potentially large
- drop in throughput on some files).
- 5/15/11 v1.09 - Initial stable release.
-
- * Low-level Deflate/Inflate implementation notes:
-
- Compression: Use the "tdefl" API's. The compressor supports raw, static,
- and dynamic blocks, lazy or
- greedy parsing, match length filtering, RLE-only, and Huffman-only streams.
- It performs and compresses
- approximately as well as zlib.
-
- Decompression: Use the "tinfl" API's. The entire decompressor is
- implemented as a single function
- coroutine: see tinfl_decompress(). It supports decompression into a 32KB
- (or larger power of 2) wrapping buffer, or into a memory
- block large enough to hold the entire file.
-
- The low-level tdefl/tinfl API's do not make any use of dynamic memory
- allocation.
-
- * zlib-style API notes:
-
- miniz.c implements a fairly large subset of zlib. There's enough
- functionality present for it to be a drop-in
- zlib replacement in many apps:
- The z_stream struct, optional memory allocation callbacks
- deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound
- inflateInit/inflateInit2/inflate/inflateEnd
- compress, compress2, compressBound, uncompress
- CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly
- routines.
- Supports raw deflate streams or standard zlib streams with adler-32
- checking.
-
- Limitations:
- The callback API's are not implemented yet. No support for gzip headers or
- zlib static dictionaries.
- I've tried to closely emulate zlib's various flavors of stream flushing
- and return status codes, but
- there are no guarantees that miniz.c pulls this off perfectly.
-
- * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function,
- originally written by
- Alex Evans. Supports 1-4 bytes/pixel images.
-
- * ZIP archive API notes:
-
- The ZIP archive API's where designed with simplicity and efficiency in
- mind, with just enough abstraction to
- get the job done with minimal fuss. There are simple API's to retrieve file
- information, read files from
- existing archives, create new archives, append new files to existing
- archives, or clone archive data from
- one archive to another. It supports archives located in memory or the heap,
- on disk (using stdio.h),
- or you can specify custom file read/write callbacks.
-
- - Archive reading: Just call this function to read a single file from a
- disk archive:
-
- void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const
- char *pArchive_name,
- size_t *pSize, mz_uint zip_flags);
-
- For more complex cases, use the "mz_zip_reader" functions. Upon opening an
- archive, the entire central
- directory is located and read as-is into memory, and subsequent file access
- only occurs when reading individual files.
-
- - Archives file scanning: The simple way is to use this function to scan a
- loaded archive for a specific file:
-
- int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName,
- const char *pComment, mz_uint flags);
-
- The locate operation can optionally check file comments too, which (as one
- example) can be used to identify
- multiple versions of the same file in an archive. This function uses a
- simple linear search through the central
- directory, so it's not very fast.
-
- Alternately, you can iterate through all the files in an archive (using
- mz_zip_reader_get_num_files()) and
- retrieve detailed info on each file by calling mz_zip_reader_file_stat().
-
- - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer
- immediately writes compressed file data
- to disk and builds an exact image of the central directory in memory. The
- central directory image is written
- all at once at the end of the archive file when the archive is finalized.
-
- The archive writer can optionally align each file's local header and file
- data to any power of 2 alignment,
- which can be useful when the archive will be read from optical media. Also,
- the writer supports placing
- arbitrary data blobs at the very beginning of ZIP archives. Archives
- written using either feature are still
- readable by any ZIP tool.
-
- - Archive appending: The simple way to add a single file to an archive is
- to call this function:
-
- mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename,
- const char *pArchive_name,
- const void *pBuf, size_t buf_size, const void *pComment, mz_uint16
- comment_size, mz_uint level_and_flags);
-
- The archive will be created if it doesn't already exist, otherwise it'll be
- appended to.
- Note the appending is done in-place and is not an atomic operation, so if
- something goes wrong
- during the operation it's possible the archive could be left without a
- central directory (although the local
- file headers and file data will be fine, so the archive will be
- recoverable).
-
- For more complex archive modification scenarios:
- 1. The safest way is to use a mz_zip_reader to read the existing archive,
- cloning only those bits you want to
- preserve into a new archive using using the
- mz_zip_writer_add_from_zip_reader() function (which compiles the
- compressed file data as-is). When you're done, delete the old archive and
- rename the newly written archive, and
- you're done. This is safe but requires a bunch of temporary disk space or
- heap memory.
-
- 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using
- mz_zip_writer_init_from_reader(),
- append new files as needed, then finalize the archive which will write an
- updated central directory to the
- original archive. (This is basically what
- mz_zip_add_mem_to_archive_file_in_place() does.) There's a
- possibility that the archive's central directory could be lost with this
- method if anything goes wrong, though.
-
- - ZIP archive support limitations:
- No zip64 or spanning support. Extraction functions can only handle
- unencrypted, stored or deflated files.
- Requires streams capable of seeking.
-
- * This is a header file library, like stb_image.c. To get only a header file,
- either cut and paste the
- below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then
- include miniz.c from it.
-
- * Important: For best perf. be sure to customize the below macros for your
- target platform:
- #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
- #define MINIZ_LITTLE_ENDIAN 1
- #define MINIZ_HAS_64BIT_REGISTERS 1
-
- * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before
- including miniz.c to ensure miniz
- uses the 64-bit variants: fopen64(), stat64(), etc. Otherwise you won't be
- able to process large files
- (i.e. 32-bit stat() fails for me on files > 0x7FFFFFFF bytes).
-*/
-
-#ifndef MINIZ_HEADER_INCLUDED
-#define MINIZ_HEADER_INCLUDED
-
-//#include <stdlib.h>
-
-// Defines to completely disable specific portions of miniz.c:
-// If all macros here are defined the only functionality remaining will be
-// CRC-32, adler-32, tinfl, and tdefl.
-
-// Define MINIZ_NO_STDIO to disable all usage and any functions which rely on
-// stdio for file I/O.
-//#define MINIZ_NO_STDIO
-
-// If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able
-// to get the current time, or
-// get/set file times, and the C run-time funcs that get/set times won't be
-// called.
-// The current downside is the times written to your archives will be from 1979.
-#define MINIZ_NO_TIME
-
-// Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's.
-#define MINIZ_NO_ARCHIVE_APIS
-
-// Define MINIZ_NO_ARCHIVE_APIS to disable all writing related ZIP archive
-// API's.
-//#define MINIZ_NO_ARCHIVE_WRITING_APIS
-
-// Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression
-// API's.
-//#define MINIZ_NO_ZLIB_APIS
-
-// Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent
-// conflicts against stock zlib.
-//#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES
-
-// Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc.
-// Note if MINIZ_NO_MALLOC is defined then the user must always provide custom
-// user alloc/free/realloc
-// callbacks to the zlib and archive API's, and a few stand-alone helper API's
-// which don't provide custom user
-// functions (such as tdefl_compress_mem_to_heap() and
-// tinfl_decompress_mem_to_heap()) won't work.
-//#define MINIZ_NO_MALLOC
-
-#if defined(__TINYC__) && (defined(__linux) || defined(__linux__))
-// TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc
-// on Linux
-#define MINIZ_NO_TIME
-#endif
-
-#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS)
-//#include <time.h>
-#endif
-
-#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || \
- defined(__i386) || defined(__i486__) || defined(__i486) || \
- defined(i386) || defined(__ia64__) || defined(__x86_64__)
-// MINIZ_X86_OR_X64_CPU is only used to help set the below macros.
-#define MINIZ_X86_OR_X64_CPU 1
-#endif
-
-#if defined(__sparcv9)
-// Big endian
-#else
-#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU
-// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian.
-#define MINIZ_LITTLE_ENDIAN 1
-#endif
-#endif
-
-#if MINIZ_X86_OR_X64_CPU
-// Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient
-// integer loads and stores from unaligned addresses.
-//#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
-#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES \
- 0 // disable to suppress compiler warnings
-#endif
-
-#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || \
- defined(_LP64) || defined(__LP64__) || defined(__ia64__) || \
- defined(__x86_64__)
-// Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are
-// reasonably fast (and don't involve compiler generated calls to helper
-// functions).
-#define MINIZ_HAS_64BIT_REGISTERS 1
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// ------------------- zlib-style API Definitions.
-
-// For more compatibility with zlib, miniz.c uses unsigned long for some
-// parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits!
-typedef unsigned long mz_ulong;
-
-// mz_free() internally uses the MZ_FREE() macro (which by default calls free()
-// unless you've modified the MZ_MALLOC macro) to release a block allocated from
-// the heap.
-void mz_free(void *p);
-
-#define MZ_ADLER32_INIT (1)
-// mz_adler32() returns the initial adler-32 value to use when called with
-// ptr==NULL.
-mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len);
-
-#define MZ_CRC32_INIT (0)
-// mz_crc32() returns the initial CRC-32 value to use when called with
-// ptr==NULL.
-mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len);
-
-// Compression strategies.
-enum {
- MZ_DEFAULT_STRATEGY = 0,
- MZ_FILTERED = 1,
- MZ_HUFFMAN_ONLY = 2,
- MZ_RLE = 3,
- MZ_FIXED = 4
-};
-
-// Method
-#define MZ_DEFLATED 8
-
-#ifndef MINIZ_NO_ZLIB_APIS
-
-// Heap allocation callbacks.
-// Note that mz_alloc_func parameter types purpsosely differ from zlib's:
-// items/size is size_t, not unsigned long.
-typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size);
-typedef void (*mz_free_func)(void *opaque, void *address);
-typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items,
- size_t size);
-
-#define MZ_VERSION "9.1.15"
-#define MZ_VERNUM 0x91F0
-#define MZ_VER_MAJOR 9
-#define MZ_VER_MINOR 1
-#define MZ_VER_REVISION 15
-#define MZ_VER_SUBREVISION 0
-
-// Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The
-// other values are for advanced use (refer to the zlib docs).
-enum {
- MZ_NO_FLUSH = 0,
- MZ_PARTIAL_FLUSH = 1,
- MZ_SYNC_FLUSH = 2,
- MZ_FULL_FLUSH = 3,
- MZ_FINISH = 4,
- MZ_BLOCK = 5
-};
-
-// Return status codes. MZ_PARAM_ERROR is non-standard.
-enum {
- MZ_OK = 0,
- MZ_STREAM_END = 1,
- MZ_NEED_DICT = 2,
- MZ_ERRNO = -1,
- MZ_STREAM_ERROR = -2,
- MZ_DATA_ERROR = -3,
- MZ_MEM_ERROR = -4,
- MZ_BUF_ERROR = -5,
- MZ_VERSION_ERROR = -6,
- MZ_PARAM_ERROR = -10000
-};
-
-// Compression levels: 0-9 are the standard zlib-style levels, 10 is best
-// possible compression (not zlib compatible, and may be very slow),
-// MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL.
-enum {
- MZ_NO_COMPRESSION = 0,
- MZ_BEST_SPEED = 1,
- MZ_BEST_COMPRESSION = 9,
- MZ_UBER_COMPRESSION = 10,
- MZ_DEFAULT_LEVEL = 6,
- MZ_DEFAULT_COMPRESSION = -1
-};
-
-// Window bits
-#define MZ_DEFAULT_WINDOW_BITS 15
-
-struct mz_internal_state;
-
-// Compression/decompression stream struct.
-typedef struct mz_stream_s {
- const unsigned char *next_in; // pointer to next byte to read
- unsigned int avail_in; // number of bytes available at next_in
- mz_ulong total_in; // total number of bytes consumed so far
-
- unsigned char *next_out; // pointer to next byte to write
- unsigned int avail_out; // number of bytes that can be written to next_out
- mz_ulong total_out; // total number of bytes produced so far
-
- char *msg; // error msg (unused)
- struct mz_internal_state *state; // internal state, allocated by zalloc/zfree
-
- mz_alloc_func
- zalloc; // optional heap allocation function (defaults to malloc)
- mz_free_func zfree; // optional heap free function (defaults to free)
- void *opaque; // heap alloc function user pointer
-
- int data_type; // data_type (unused)
- mz_ulong adler; // adler32 of the source or uncompressed data
- mz_ulong reserved; // not used
-} mz_stream;
-
-typedef mz_stream *mz_streamp;
-
-// Returns the version string of miniz.c.
-const char *mz_version(void);
-
-// mz_deflateInit() initializes a compressor with default options:
-// Parameters:
-// pStream must point to an initialized mz_stream struct.
-// level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION].
-// level 1 enables a specially optimized compression function that's been
-// optimized purely for performance, not ratio.
-// (This special func. is currently only enabled when
-// MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.)
-// Return values:
-// MZ_OK on success.
-// MZ_STREAM_ERROR if the stream is bogus.
-// MZ_PARAM_ERROR if the input parameters are bogus.
-// MZ_MEM_ERROR on out of memory.
-int mz_deflateInit(mz_streamp pStream, int level);
-
-// mz_deflateInit2() is like mz_deflate(), except with more control:
-// Additional parameters:
-// method must be MZ_DEFLATED
-// window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with
-// zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no
-// header or footer)
-// mem_level must be between [1, 9] (it's checked but ignored by miniz.c)
-int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits,
- int mem_level, int strategy);
-
-// Quickly resets a compressor without having to reallocate anything. Same as
-// calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2().
-int mz_deflateReset(mz_streamp pStream);
-
-// mz_deflate() compresses the input to output, consuming as much of the input
-// and producing as much output as possible.
-// Parameters:
-// pStream is the stream to read from and write to. You must initialize/update
-// the next_in, avail_in, next_out, and avail_out members.
-// flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or
-// MZ_FINISH.
-// Return values:
-// MZ_OK on success (when flushing, or if more input is needed but not
-// available, and/or there's more output to be written but the output buffer
-// is full).
-// MZ_STREAM_END if all input has been consumed and all output bytes have been
-// written. Don't call mz_deflate() on the stream anymore.
-// MZ_STREAM_ERROR if the stream is bogus.
-// MZ_PARAM_ERROR if one of the parameters is invalid.
-// MZ_BUF_ERROR if no forward progress is possible because the input and/or
-// output buffers are empty. (Fill up the input buffer or free up some output
-// space and try again.)
-int mz_deflate(mz_streamp pStream, int flush);
-
-// mz_deflateEnd() deinitializes a compressor:
-// Return values:
-// MZ_OK on success.
-// MZ_STREAM_ERROR if the stream is bogus.
-int mz_deflateEnd(mz_streamp pStream);
-
-// mz_deflateBound() returns a (very) conservative upper bound on the amount of
-// data that could be generated by deflate(), assuming flush is set to only
-// MZ_NO_FLUSH or MZ_FINISH.
-mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len);
-
-// Single-call compression functions mz_compress() and mz_compress2():
-// Returns MZ_OK on success, or one of the error codes from mz_deflate() on
-// failure.
-int mz_compress(unsigned char *pDest, mz_ulong *pDest_len,
- const unsigned char *pSource, mz_ulong source_len);
-int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len,
- const unsigned char *pSource, mz_ulong source_len, int level);
-
-// mz_compressBound() returns a (very) conservative upper bound on the amount of
-// data that could be generated by calling mz_compress().
-mz_ulong mz_compressBound(mz_ulong source_len);
-
-// Initializes a decompressor.
-int mz_inflateInit(mz_streamp pStream);
-
-// mz_inflateInit2() is like mz_inflateInit() with an additional option that
-// controls the window size and whether or not the stream has been wrapped with
-// a zlib header/footer:
-// window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or
-// -MZ_DEFAULT_WINDOW_BITS (raw deflate).
-int mz_inflateInit2(mz_streamp pStream, int window_bits);
-
-// Decompresses the input stream to the output, consuming only as much of the
-// input as needed, and writing as much to the output as possible.
-// Parameters:
-// pStream is the stream to read from and write to. You must initialize/update
-// the next_in, avail_in, next_out, and avail_out members.
-// flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH.
-// On the first call, if flush is MZ_FINISH it's assumed the input and output
-// buffers are both sized large enough to decompress the entire stream in a
-// single call (this is slightly faster).
-// MZ_FINISH implies that there are no more source bytes available beside
-// what's already in the input buffer, and that the output buffer is large
-// enough to hold the rest of the decompressed data.
-// Return values:
-// MZ_OK on success. Either more input is needed but not available, and/or
-// there's more output to be written but the output buffer is full.
-// MZ_STREAM_END if all needed input has been consumed and all output bytes
-// have been written. For zlib streams, the adler-32 of the decompressed data
-// has also been verified.
-// MZ_STREAM_ERROR if the stream is bogus.
-// MZ_DATA_ERROR if the deflate stream is invalid.
-// MZ_PARAM_ERROR if one of the parameters is invalid.
-// MZ_BUF_ERROR if no forward progress is possible because the input buffer is
-// empty but the inflater needs more input to continue, or if the output
-// buffer is not large enough. Call mz_inflate() again
-// with more input data, or with more room in the output buffer (except when
-// using single call decompression, described above).
-int mz_inflate(mz_streamp pStream, int flush);
-
-// Deinitializes a decompressor.
-int mz_inflateEnd(mz_streamp pStream);
-
-// Single-call decompression.
-// Returns MZ_OK on success, or one of the error codes from mz_inflate() on
-// failure.
-int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len,
- const unsigned char *pSource, mz_ulong source_len);
-
-// Returns a string description of the specified error code, or NULL if the
-// error code is invalid.
-const char *mz_error(int err);
-
-// Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used
-// as a drop-in replacement for the subset of zlib that miniz.c supports.
-// Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you
-// use zlib in the same project.
-#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES
-typedef unsigned char Byte;
-typedef unsigned int uInt;
-typedef mz_ulong uLong;
-typedef Byte Bytef;
-typedef uInt uIntf;
-typedef char charf;
-typedef int intf;
-typedef void *voidpf;
-typedef uLong uLongf;
-typedef void *voidp;
-typedef void *const voidpc;
-#define Z_NULL 0
-#define Z_NO_FLUSH MZ_NO_FLUSH
-#define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH
-#define Z_SYNC_FLUSH MZ_SYNC_FLUSH
-#define Z_FULL_FLUSH MZ_FULL_FLUSH
-#define Z_FINISH MZ_FINISH
-#define Z_BLOCK MZ_BLOCK
-#define Z_OK MZ_OK
-#define Z_STREAM_END MZ_STREAM_END
-#define Z_NEED_DICT MZ_NEED_DICT
-#define Z_ERRNO MZ_ERRNO
-#define Z_STREAM_ERROR MZ_STREAM_ERROR
-#define Z_DATA_ERROR MZ_DATA_ERROR
-#define Z_MEM_ERROR MZ_MEM_ERROR
-#define Z_BUF_ERROR MZ_BUF_ERROR
-#define Z_VERSION_ERROR MZ_VERSION_ERROR
-#define Z_PARAM_ERROR MZ_PARAM_ERROR
-#define Z_NO_COMPRESSION MZ_NO_COMPRESSION
-#define Z_BEST_SPEED MZ_BEST_SPEED
-#define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION
-#define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION
-#define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY
-#define Z_FILTERED MZ_FILTERED
-#define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY
-#define Z_RLE MZ_RLE
-#define Z_FIXED MZ_FIXED
-#define Z_DEFLATED MZ_DEFLATED
-#define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS
-#define alloc_func mz_alloc_func
-#define free_func mz_free_func
-#define internal_state mz_internal_state
-#define z_stream mz_stream
-#define deflateInit mz_deflateInit
-#define deflateInit2 mz_deflateInit2
-#define deflateReset mz_deflateReset
-#define deflate mz_deflate
-#define deflateEnd mz_deflateEnd
-#define deflateBound mz_deflateBound
-#define compress mz_compress
-#define compress2 mz_compress2
-#define compressBound mz_compressBound
-#define inflateInit mz_inflateInit
-#define inflateInit2 mz_inflateInit2
-#define inflate mz_inflate
-#define inflateEnd mz_inflateEnd
-#define uncompress mz_uncompress
-#define crc32 mz_crc32
-#define adler32 mz_adler32
-#define MAX_WBITS 15
-#define MAX_MEM_LEVEL 9
-#define zError mz_error
-#define ZLIB_VERSION MZ_VERSION
-#define ZLIB_VERNUM MZ_VERNUM
-#define ZLIB_VER_MAJOR MZ_VER_MAJOR
-#define ZLIB_VER_MINOR MZ_VER_MINOR
-#define ZLIB_VER_REVISION MZ_VER_REVISION
-#define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION
-#define zlibVersion mz_version
-#define zlib_version mz_version()
-#endif // #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES
-
-#endif // MINIZ_NO_ZLIB_APIS
-
-// ------------------- Types and macros
-
-typedef unsigned char mz_uint8;
-typedef signed short mz_int16;
-typedef unsigned short mz_uint16;
-typedef unsigned int mz_uint32;
-typedef unsigned int mz_uint;
-typedef long long mz_int64;
-typedef unsigned long long mz_uint64;
-typedef int mz_bool;
-
-#define MZ_FALSE (0)
-#define MZ_TRUE (1)
-
-// An attempt to work around MSVC's spammy "warning C4127: conditional
-// expression is constant" message.
-#ifdef _MSC_VER
-#define MZ_MACRO_END while (0, 0)
-#else
-#define MZ_MACRO_END while (0)
-#endif
-
-// ------------------- ZIP archive reading/writing
-
-#ifndef MINIZ_NO_ARCHIVE_APIS
-
-enum {
- MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024,
- MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 260,
- MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 256
-};
-
-typedef struct {
- mz_uint32 m_file_index;
- mz_uint32 m_central_dir_ofs;
- mz_uint16 m_version_made_by;
- mz_uint16 m_version_needed;
- mz_uint16 m_bit_flag;
- mz_uint16 m_method;
-#ifndef MINIZ_NO_TIME
- time_t m_time;
-#endif
- mz_uint32 m_crc32;
- mz_uint64 m_comp_size;
- mz_uint64 m_uncomp_size;
- mz_uint16 m_internal_attr;
- mz_uint32 m_external_attr;
- mz_uint64 m_local_header_ofs;
- mz_uint32 m_comment_size;
- char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE];
- char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE];
-} mz_zip_archive_file_stat;
-
-typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs,
- void *pBuf, size_t n);
-typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs,
- const void *pBuf, size_t n);
-
-struct mz_zip_internal_state_tag;
-typedef struct mz_zip_internal_state_tag mz_zip_internal_state;
-
-typedef enum {
- MZ_ZIP_MODE_INVALID = 0,
- MZ_ZIP_MODE_READING = 1,
- MZ_ZIP_MODE_WRITING = 2,
- MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3
-} mz_zip_mode;
-
-typedef struct mz_zip_archive_tag {
- mz_uint64 m_archive_size;
- mz_uint64 m_central_directory_file_ofs;
- mz_uint m_total_files;
- mz_zip_mode m_zip_mode;
-
- mz_uint m_file_offset_alignment;
-
- mz_alloc_func m_pAlloc;
- mz_free_func m_pFree;
- mz_realloc_func m_pRealloc;
- void *m_pAlloc_opaque;
-
- mz_file_read_func m_pRead;
- mz_file_write_func m_pWrite;
- void *m_pIO_opaque;
-
- mz_zip_internal_state *m_pState;
-
-} mz_zip_archive;
-
-typedef enum {
- MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100,
- MZ_ZIP_FLAG_IGNORE_PATH = 0x0200,
- MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400,
- MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800
-} mz_zip_flags;
-
-// ZIP archive reading
-
-// Inits a ZIP archive reader.
-// These functions read and validate the archive's central directory.
-mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size,
- mz_uint32 flags);
-mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem,
- size_t size, mz_uint32 flags);
-
-#ifndef MINIZ_NO_STDIO
-mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename,
- mz_uint32 flags);
-#endif
-
-// Returns the total number of files in the archive.
-mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip);
-
-// Returns detailed information about an archive file entry.
-mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index,
- mz_zip_archive_file_stat *pStat);
-
-// Determines if an archive file entry is a directory entry.
-mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip,
- mz_uint file_index);
-mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip,
- mz_uint file_index);
-
-// Retrieves the filename of an archive file entry.
-// Returns the number of bytes written to pFilename, or if filename_buf_size is
-// 0 this function returns the number of bytes needed to fully store the
-// filename.
-mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index,
- char *pFilename, mz_uint filename_buf_size);
-
-// Attempts to locates a file in the archive's central directory.
-// Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH
-// Returns -1 if the file cannot be found.
-int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName,
- const char *pComment, mz_uint flags);
-
-// Extracts a archive file to a memory buffer using no memory allocation.
-mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip,
- mz_uint file_index, void *pBuf,
- size_t buf_size, mz_uint flags,
- void *pUser_read_buf,
- size_t user_read_buf_size);
-mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(
- mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size,
- mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size);
-
-// Extracts a archive file to a memory buffer.
-mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index,
- void *pBuf, size_t buf_size,
- mz_uint flags);
-mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip,
- const char *pFilename, void *pBuf,
- size_t buf_size, mz_uint flags);
-
-// Extracts a archive file to a dynamically allocated heap buffer.
-void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index,
- size_t *pSize, mz_uint flags);
-void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip,
- const char *pFilename, size_t *pSize,
- mz_uint flags);
-
-// Extracts a archive file using a callback function to output the file's data.
-mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip,
- mz_uint file_index,
- mz_file_write_func pCallback,
- void *pOpaque, mz_uint flags);
-mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip,
- const char *pFilename,
- mz_file_write_func pCallback,
- void *pOpaque, mz_uint flags);
-
-#ifndef MINIZ_NO_STDIO
-// Extracts a archive file to a disk file and sets its last accessed and
-// modified times.
-// This function only extracts files, not archive directory records.
-mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index,
- const char *pDst_filename, mz_uint flags);
-mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip,
- const char *pArchive_filename,
- const char *pDst_filename,
- mz_uint flags);
-#endif
-
-// Ends archive reading, freeing all allocations, and closing the input archive
-// file if mz_zip_reader_init_file() was used.
-mz_bool mz_zip_reader_end(mz_zip_archive *pZip);
-
-// ZIP archive writing
-
-#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
-
-// Inits a ZIP archive writer.
-mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size);
-mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip,
- size_t size_to_reserve_at_beginning,
- size_t initial_allocation_size);
-
-#ifndef MINIZ_NO_STDIO
-mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename,
- mz_uint64 size_to_reserve_at_beginning);
-#endif
-
-// Converts a ZIP archive reader object into a writer object, to allow efficient
-// in-place file appends to occur on an existing archive.
-// For archives opened using mz_zip_reader_init_file, pFilename must be the
-// archive's filename so it can be reopened for writing. If the file can't be
-// reopened, mz_zip_reader_end() will be called.
-// For archives opened using mz_zip_reader_init_mem, the memory block must be
-// growable using the realloc callback (which defaults to realloc unless you've
-// overridden it).
-// Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's
-// user provided m_pWrite function cannot be NULL.
-// Note: In-place archive modification is not recommended unless you know what
-// you're doing, because if execution stops or something goes wrong before
-// the archive is finalized the file's central directory will be hosed.
-mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip,
- const char *pFilename);
-
-// Adds the contents of a memory buffer to an archive. These functions record
-// the current local time into the archive.
-// To add a directory entry, call this method with an archive name ending in a
-// forwardslash with empty buffer.
-// level_and_flags - compression level (0-10, see MZ_BEST_SPEED,
-// MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or
-// just set to MZ_DEFAULT_COMPRESSION.
-mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name,
- const void *pBuf, size_t buf_size,
- mz_uint level_and_flags);
-mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip,
- const char *pArchive_name, const void *pBuf,
- size_t buf_size, const void *pComment,
- mz_uint16 comment_size,
- mz_uint level_and_flags, mz_uint64 uncomp_size,
- mz_uint32 uncomp_crc32);
-
-#ifndef MINIZ_NO_STDIO
-// Adds the contents of a disk file to an archive. This function also records
-// the disk file's modified time into the archive.
-// level_and_flags - compression level (0-10, see MZ_BEST_SPEED,
-// MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or
-// just set to MZ_DEFAULT_COMPRESSION.
-mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name,
- const char *pSrc_filename, const void *pComment,
- mz_uint16 comment_size, mz_uint level_and_flags);
-#endif
-
-// Adds a file to an archive by fully cloning the data from another archive.
-// This function fully clones the source file's compressed data (no
-// recompression), along with its full filename, extra data, and comment fields.
-mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip,
- mz_zip_archive *pSource_zip,
- mz_uint file_index);
-
-// Finalizes the archive by writing the central directory records followed by
-// the end of central directory record.
-// After an archive is finalized, the only valid call on the mz_zip_archive
-// struct is mz_zip_writer_end().
-// An archive must be manually finalized by calling this function for it to be
-// valid.
-mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip);
-mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf,
- size_t *pSize);
-
-// Ends archive writing, freeing all allocations, and closing the output file if
-// mz_zip_writer_init_file() was used.
-// Note for the archive to be valid, it must have been finalized before ending.
-mz_bool mz_zip_writer_end(mz_zip_archive *pZip);
-
-// Misc. high-level helper functions:
-
-// mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically)
-// appends a memory blob to a ZIP archive.
-// level_and_flags - compression level (0-10, see MZ_BEST_SPEED,
-// MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or
-// just set to MZ_DEFAULT_COMPRESSION.
-mz_bool mz_zip_add_mem_to_archive_file_in_place(
- const char *pZip_filename, const char *pArchive_name, const void *pBuf,
- size_t buf_size, const void *pComment, mz_uint16 comment_size,
- mz_uint level_and_flags);
-
-// Reads a single file from an archive into a heap block.
-// Returns NULL on failure.
-void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename,
- const char *pArchive_name,
- size_t *pSize, mz_uint zip_flags);
-
-#endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
-
-#endif // #ifndef MINIZ_NO_ARCHIVE_APIS
-
-// ------------------- Low-level Decompression API Definitions
-
-// Decompression flags used by tinfl_decompress().
-// TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and
-// ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the
-// input is a raw deflate stream.
-// TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available
-// beyond the end of the supplied input buffer. If clear, the input buffer
-// contains all remaining input.
-// TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large
-// enough to hold the entire decompressed stream. If clear, the output buffer is
-// at least the size of the dictionary (typically 32KB).
-// TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the
-// decompressed bytes.
-enum {
- TINFL_FLAG_PARSE_ZLIB_HEADER = 1,
- TINFL_FLAG_HAS_MORE_INPUT = 2,
- TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4,
- TINFL_FLAG_COMPUTE_ADLER32 = 8
-};
-
-// High level decompression functions:
-// tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block
-// allocated via malloc().
-// On entry:
-// pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data
-// to decompress.
-// On return:
-// Function returns a pointer to the decompressed data, or NULL on failure.
-// *pOut_len will be set to the decompressed data's size, which could be larger
-// than src_buf_len on uncompressible data.
-// The caller must call mz_free() on the returned block when it's no longer
-// needed.
-void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len,
- size_t *pOut_len, int flags);
-
-// tinfl_decompress_mem_to_mem() decompresses a block in memory to another block
-// in memory.
-// Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes
-// written on success.
-#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1))
-size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len,
- const void *pSrc_buf, size_t src_buf_len,
- int flags);
-
-// tinfl_decompress_mem_to_callback() decompresses a block in memory to an
-// internal 32KB buffer, and a user provided callback function will be called to
-// flush the buffer.
-// Returns 1 on success or 0 on failure.
-typedef int (*tinfl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser);
-int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size,
- tinfl_put_buf_func_ptr pPut_buf_func,
- void *pPut_buf_user, int flags);
-
-struct tinfl_decompressor_tag;
-typedef struct tinfl_decompressor_tag tinfl_decompressor;
-
-// Max size of LZ dictionary.
-#define TINFL_LZ_DICT_SIZE 32768
-
-// Return status.
-typedef enum {
- TINFL_STATUS_BAD_PARAM = -3,
- TINFL_STATUS_ADLER32_MISMATCH = -2,
- TINFL_STATUS_FAILED = -1,
- TINFL_STATUS_DONE = 0,
- TINFL_STATUS_NEEDS_MORE_INPUT = 1,
- TINFL_STATUS_HAS_MORE_OUTPUT = 2
-} tinfl_status;
-
-// Initializes the decompressor to its initial state.
-#define tinfl_init(r) \
- do { \
- (r)->m_state = 0; \
- } \
- MZ_MACRO_END
-#define tinfl_get_adler32(r) (r)->m_check_adler32
-
-// Main low-level decompressor coroutine function. This is the only function
-// actually needed for decompression. All the other functions are just
-// high-level helpers for improved usability.
-// This is a universal API, i.e. it can be used as a building block to build any
-// desired higher level decompression API. In the limit case, it can be called
-// once per every byte input or output.
-tinfl_status tinfl_decompress(tinfl_decompressor *r,
- const mz_uint8 *pIn_buf_next,
- size_t *pIn_buf_size, mz_uint8 *pOut_buf_start,
- mz_uint8 *pOut_buf_next, size_t *pOut_buf_size,
- const mz_uint32 decomp_flags);
-
-// Internal/private bits follow.
-enum {
- TINFL_MAX_HUFF_TABLES = 3,
- TINFL_MAX_HUFF_SYMBOLS_0 = 288,
- TINFL_MAX_HUFF_SYMBOLS_1 = 32,
- TINFL_MAX_HUFF_SYMBOLS_2 = 19,
- TINFL_FAST_LOOKUP_BITS = 10,
- TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS
-};
-
-typedef struct {
- mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0];
- mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE],
- m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2];
-} tinfl_huff_table;
-
-#if MINIZ_HAS_64BIT_REGISTERS
-#define TINFL_USE_64BIT_BITBUF 1
-#endif
-
-#if TINFL_USE_64BIT_BITBUF
-typedef mz_uint64 tinfl_bit_buf_t;
-#define TINFL_BITBUF_SIZE (64)
-#else
-typedef mz_uint32 tinfl_bit_buf_t;
-#define TINFL_BITBUF_SIZE (32)
-#endif
-
-struct tinfl_decompressor_tag {
- mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type,
- m_check_adler32, m_dist, m_counter, m_num_extra,
- m_table_sizes[TINFL_MAX_HUFF_TABLES];
- tinfl_bit_buf_t m_bit_buf;
- size_t m_dist_from_out_buf_start;
- tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES];
- mz_uint8 m_raw_header[4],
- m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137];
-};
-
-// ------------------- Low-level Compression API Definitions
-
-// Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly
-// slower, and raw/dynamic blocks will be output more frequently).
-#define TDEFL_LESS_MEMORY 0
-
-// tdefl_init() compression flags logically OR'd together (low 12 bits contain
-// the max. number of probes per dictionary search):
-// TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes
-// per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap
-// compression), 4095=Huffman+LZ (slowest/best compression).
-enum {
- TDEFL_HUFFMAN_ONLY = 0,
- TDEFL_DEFAULT_MAX_PROBES = 128,
- TDEFL_MAX_PROBES_MASK = 0xFFF
-};
-
-// TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before
-// the deflate data, and the Adler-32 of the source data at the end. Otherwise,
-// you'll get raw deflate data.
-// TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even
-// when not writing zlib headers).
-// TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more
-// efficient lazy parsing.
-// TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's
-// initialization time to the minimum, but the output may vary from run to run
-// given the same input (depending on the contents of memory).
-// TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1)
-// TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled.
-// TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables.
-// TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks.
-// The low 12 bits are reserved to control the max # of hash probes per
-// dictionary lookup (see TDEFL_MAX_PROBES_MASK).
-enum {
- TDEFL_WRITE_ZLIB_HEADER = 0x01000,
- TDEFL_COMPUTE_ADLER32 = 0x02000,
- TDEFL_GREEDY_PARSING_FLAG = 0x04000,
- TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000,
- TDEFL_RLE_MATCHES = 0x10000,
- TDEFL_FILTER_MATCHES = 0x20000,
- TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000,
- TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000
-};
-
-// High level compression functions:
-// tdefl_compress_mem_to_heap() compresses a block in memory to a heap block
-// allocated via malloc().
-// On entry:
-// pSrc_buf, src_buf_len: Pointer and size of source block to compress.
-// flags: The max match finder probes (default is 128) logically OR'd against
-// the above flags. Higher probes are slower but improve compression.
-// On return:
-// Function returns a pointer to the compressed data, or NULL on failure.
-// *pOut_len will be set to the compressed data's size, which could be larger
-// than src_buf_len on uncompressible data.
-// The caller must free() the returned block when it's no longer needed.
-void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len,
- size_t *pOut_len, int flags);
-
-// tdefl_compress_mem_to_mem() compresses a block in memory to another block in
-// memory.
-// Returns 0 on failure.
-size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len,
- const void *pSrc_buf, size_t src_buf_len,
- int flags);
-
-// Compresses an image to a compressed PNG file in memory.
-// On entry:
-// pImage, w, h, and num_chans describe the image to compress. num_chans may be
-// 1, 2, 3, or 4.
-// The image pitch in bytes per scanline will be w*num_chans. The leftmost
-// pixel on the top scanline is stored first in memory.
-// level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED,
-// MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL
-// If flip is true, the image will be flipped on the Y axis (useful for OpenGL
-// apps).
-// On return:
-// Function returns a pointer to the compressed data, or NULL on failure.
-// *pLen_out will be set to the size of the PNG image file.
-// The caller must mz_free() the returned heap block (which will typically be
-// larger than *pLen_out) when it's no longer needed.
-void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w,
- int h, int num_chans,
- size_t *pLen_out,
- mz_uint level, mz_bool flip);
-void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h,
- int num_chans, size_t *pLen_out);
-
-// Output stream interface. The compressor uses this interface to write
-// compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time.
-typedef mz_bool (*tdefl_put_buf_func_ptr)(const void *pBuf, int len,
- void *pUser);
-
-// tdefl_compress_mem_to_output() compresses a block to an output stream. The
-// above helpers use this function internally.
-mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len,
- tdefl_put_buf_func_ptr pPut_buf_func,
- void *pPut_buf_user, int flags);
-
-enum {
- TDEFL_MAX_HUFF_TABLES = 3,
- TDEFL_MAX_HUFF_SYMBOLS_0 = 288,
- TDEFL_MAX_HUFF_SYMBOLS_1 = 32,
- TDEFL_MAX_HUFF_SYMBOLS_2 = 19,
- TDEFL_LZ_DICT_SIZE = 32768,
- TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1,
- TDEFL_MIN_MATCH_LEN = 3,
- TDEFL_MAX_MATCH_LEN = 258
-};
-
-// TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed
-// output block (using static/fixed Huffman codes).
-#if TDEFL_LESS_MEMORY
-enum {
- TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024,
- TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10,
- TDEFL_MAX_HUFF_SYMBOLS = 288,
- TDEFL_LZ_HASH_BITS = 12,
- TDEFL_LEVEL1_HASH_SIZE_MASK = 4095,
- TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3,
- TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS
-};
-#else
-enum {
- TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024,
- TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10,
- TDEFL_MAX_HUFF_SYMBOLS = 288,
- TDEFL_LZ_HASH_BITS = 15,
- TDEFL_LEVEL1_HASH_SIZE_MASK = 4095,
- TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3,
- TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS
-};
-#endif
-
-// The low-level tdefl functions below may be used directly if the above helper
-// functions aren't flexible enough. The low-level functions don't make any heap
-// allocations, unlike the above helper functions.
-typedef enum {
- TDEFL_STATUS_BAD_PARAM = -2,
- TDEFL_STATUS_PUT_BUF_FAILED = -1,
- TDEFL_STATUS_OKAY = 0,
- TDEFL_STATUS_DONE = 1
-} tdefl_status;
-
-// Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums
-typedef enum {
- TDEFL_NO_FLUSH = 0,
- TDEFL_SYNC_FLUSH = 2,
- TDEFL_FULL_FLUSH = 3,
- TDEFL_FINISH = 4
-} tdefl_flush;
-
-// tdefl's compression state structure.
-typedef struct {
- tdefl_put_buf_func_ptr m_pPut_buf_func;
- void *m_pPut_buf_user;
- mz_uint m_flags, m_max_probes[2];
- int m_greedy_parsing;
- mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size;
- mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end;
- mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in,
- m_bit_buffer;
- mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit,
- m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index,
- m_wants_to_finish;
- tdefl_status m_prev_return_status;
- const void *m_pIn_buf;
- void *m_pOut_buf;
- size_t *m_pIn_buf_size, *m_pOut_buf_size;
- tdefl_flush m_flush;
- const mz_uint8 *m_pSrc;
- size_t m_src_buf_left, m_out_buf_ofs;
- mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1];
- mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
- mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
- mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
- mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE];
- mz_uint16 m_next[TDEFL_LZ_DICT_SIZE];
- mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE];
- mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE];
-} tdefl_compressor;
-
-// Initializes the compressor.
-// There is no corresponding deinit() function because the tdefl API's do not
-// dynamically allocate memory.
-// pBut_buf_func: If NULL, output data will be supplied to the specified
-// callback. In this case, the user should call the tdefl_compress_buffer() API
-// for compression.
-// If pBut_buf_func is NULL the user should always call the tdefl_compress()
-// API.
-// flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER,
-// etc.)
-tdefl_status tdefl_init(tdefl_compressor *d,
- tdefl_put_buf_func_ptr pPut_buf_func,
- void *pPut_buf_user, int flags);
-
-// Compresses a block of data, consuming as much of the specified input buffer
-// as possible, and writing as much compressed data to the specified output
-// buffer as possible.
-tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf,
- size_t *pIn_buf_size, void *pOut_buf,
- size_t *pOut_buf_size, tdefl_flush flush);
-
-// tdefl_compress_buffer() is only usable when the tdefl_init() is called with a
-// non-NULL tdefl_put_buf_func_ptr.
-// tdefl_compress_buffer() always consumes the entire input buffer.
-tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf,
- size_t in_buf_size, tdefl_flush flush);
-
-tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d);
-mz_uint32 tdefl_get_adler32(tdefl_compressor *d);
-
-// Can't use tdefl_create_comp_flags_from_zip_params if MINIZ_NO_ZLIB_APIS isn't
-// defined, because it uses some of its macros.
-#ifndef MINIZ_NO_ZLIB_APIS
-// Create tdefl_compress() flags given zlib-style compression parameters.
-// level may range from [0,10] (where 10 is absolute max compression, but may be
-// much slower on some files)
-// window_bits may be -15 (raw deflate) or 15 (zlib)
-// strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY,
-// MZ_RLE, or MZ_FIXED
-mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits,
- int strategy);
-#endif // #ifndef MINIZ_NO_ZLIB_APIS
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // MINIZ_HEADER_INCLUDED
-
-// ------------------- End of Header: Implementation follows. (If you only want
-// the header, define MINIZ_HEADER_FILE_ONLY.)
-
-#ifndef MINIZ_HEADER_FILE_ONLY
-
-typedef unsigned char mz_validate_uint16[sizeof(mz_uint16) == 2 ? 1 : -1];
-typedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1];
-typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1];
-
-//#include <assert.h>
-//#include <string.h>
-
-#define MZ_ASSERT(x) assert(x)
-
-#ifdef MINIZ_NO_MALLOC
-#define MZ_MALLOC(x) NULL
-#define MZ_FREE(x) (void)x, ((void)0)
-#define MZ_REALLOC(p, x) NULL
-#else
-#define MZ_MALLOC(x) malloc(x)
-#define MZ_FREE(x) free(x)
-#define MZ_REALLOC(p, x) realloc(p, x)
-#endif
-
-#define MZ_MAX(a, b) (((a) > (b)) ? (a) : (b))
-#define MZ_MIN(a, b) (((a) < (b)) ? (a) : (b))
-#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj))
-
-#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
-#define MZ_READ_LE16(p) *((const mz_uint16 *)(p))
-#define MZ_READ_LE32(p) *((const mz_uint32 *)(p))
-#else
-#define MZ_READ_LE16(p) \
- ((mz_uint32)(((const mz_uint8 *)(p))[0]) | \
- ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U))
-#define MZ_READ_LE32(p) \
- ((mz_uint32)(((const mz_uint8 *)(p))[0]) | \
- ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | \
- ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | \
- ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U))
-#endif
-
-#ifdef _MSC_VER
-#define MZ_FORCEINLINE __forceinline
-#elif defined(__GNUC__)
-#define MZ_FORCEINLINE inline __attribute__((__always_inline__))
-#else
-#define MZ_FORCEINLINE inline
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// ------------------- zlib-style API's
-
-mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) {
- mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16);
- size_t block_len = buf_len % 5552;
- if (!ptr) return MZ_ADLER32_INIT;
- while (buf_len) {
- for (i = 0; i + 7 < block_len; i += 8, ptr += 8) {
- s1 += ptr[0], s2 += s1;
- s1 += ptr[1], s2 += s1;
- s1 += ptr[2], s2 += s1;
- s1 += ptr[3], s2 += s1;
- s1 += ptr[4], s2 += s1;
- s1 += ptr[5], s2 += s1;
- s1 += ptr[6], s2 += s1;
- s1 += ptr[7], s2 += s1;
- }
- for (; i < block_len; ++i) s1 += *ptr++, s2 += s1;
- s1 %= 65521U, s2 %= 65521U;
- buf_len -= block_len;
- block_len = 5552;
- }
- return (s2 << 16) + s1;
-}
-
-// Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C
-// implementation that balances processor cache usage against speed":
-// http://www.geocities.com/malbrain/
-mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) {
- static const mz_uint32 s_crc32[16] = {
- 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4,
- 0x4db26158, 0x5005713c, 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
- 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c};
- mz_uint32 crcu32 = (mz_uint32)crc;
- if (!ptr) return MZ_CRC32_INIT;
- crcu32 = ~crcu32;
- while (buf_len--) {
- mz_uint8 b = *ptr++;
- crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)];
- crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)];
- }
- return ~crcu32;
-}
-
-void mz_free(void *p) { MZ_FREE(p); }
-
-#ifndef MINIZ_NO_ZLIB_APIS
-
-static void *def_alloc_func(void *opaque, size_t items, size_t size) {
- (void)opaque, (void)items, (void)size;
- return MZ_MALLOC(items * size);
-}
-static void def_free_func(void *opaque, void *address) {
- (void)opaque, (void)address;
- MZ_FREE(address);
-}
-// static void *def_realloc_func(void *opaque, void *address, size_t items,
-// size_t size) {
-// (void)opaque, (void)address, (void)items, (void)size;
-// return MZ_REALLOC(address, items * size);
-//}
-
-const char *mz_version(void) { return MZ_VERSION; }
-
-int mz_deflateInit(mz_streamp pStream, int level) {
- return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9,
- MZ_DEFAULT_STRATEGY);
-}
-
-int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits,
- int mem_level, int strategy) {
- tdefl_compressor *pComp;
- mz_uint comp_flags =
- TDEFL_COMPUTE_ADLER32 |
- tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy);
-
- if (!pStream) return MZ_STREAM_ERROR;
- if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) ||
- ((window_bits != MZ_DEFAULT_WINDOW_BITS) &&
- (-window_bits != MZ_DEFAULT_WINDOW_BITS)))
- return MZ_PARAM_ERROR;
-
- pStream->data_type = 0;
- pStream->adler = MZ_ADLER32_INIT;
- pStream->msg = NULL;
- pStream->reserved = 0;
- pStream->total_in = 0;
- pStream->total_out = 0;
- if (!pStream->zalloc) pStream->zalloc = def_alloc_func;
- if (!pStream->zfree) pStream->zfree = def_free_func;
-
- pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1,
- sizeof(tdefl_compressor));
- if (!pComp) return MZ_MEM_ERROR;
-
- pStream->state = (struct mz_internal_state *)pComp;
-
- if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) {
- mz_deflateEnd(pStream);
- return MZ_PARAM_ERROR;
- }
-
- return MZ_OK;
-}
-
-int mz_deflateReset(mz_streamp pStream) {
- if ((!pStream) || (!pStream->state) || (!pStream->zalloc) ||
- (!pStream->zfree))
- return MZ_STREAM_ERROR;
- pStream->total_in = pStream->total_out = 0;
- tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL,
- ((tdefl_compressor *)pStream->state)->m_flags);
- return MZ_OK;
-}
-
-int mz_deflate(mz_streamp pStream, int flush) {
- size_t in_bytes, out_bytes;
- mz_ulong orig_total_in, orig_total_out;
- int mz_status = MZ_OK;
-
- if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) ||
- (!pStream->next_out))
- return MZ_STREAM_ERROR;
- if (!pStream->avail_out) return MZ_BUF_ERROR;
-
- if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH;
-
- if (((tdefl_compressor *)pStream->state)->m_prev_return_status ==
- TDEFL_STATUS_DONE)
- return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR;
-
- orig_total_in = pStream->total_in;
- orig_total_out = pStream->total_out;
- for (;;) {
- tdefl_status defl_status;
- in_bytes = pStream->avail_in;
- out_bytes = pStream->avail_out;
-
- defl_status = tdefl_compress((tdefl_compressor *)pStream->state,
- pStream->next_in, &in_bytes, pStream->next_out,
- &out_bytes, (tdefl_flush)flush);
- pStream->next_in += (mz_uint)in_bytes;
- pStream->avail_in -= (mz_uint)in_bytes;
- pStream->total_in += (mz_uint)in_bytes;
- pStream->adler = tdefl_get_adler32((tdefl_compressor *)pStream->state);
-
- pStream->next_out += (mz_uint)out_bytes;
- pStream->avail_out -= (mz_uint)out_bytes;
- pStream->total_out += (mz_uint)out_bytes;
-
- if (defl_status < 0) {
- mz_status = MZ_STREAM_ERROR;
- break;
- } else if (defl_status == TDEFL_STATUS_DONE) {
- mz_status = MZ_STREAM_END;
- break;
- } else if (!pStream->avail_out)
- break;
- else if ((!pStream->avail_in) && (flush != MZ_FINISH)) {
- if ((flush) || (pStream->total_in != orig_total_in) ||
- (pStream->total_out != orig_total_out))
- break;
- return MZ_BUF_ERROR; // Can't make forward progress without some input.
- }
- }
- return mz_status;
-}
-
-int mz_deflateEnd(mz_streamp pStream) {
- if (!pStream) return MZ_STREAM_ERROR;
- if (pStream->state) {
- pStream->zfree(pStream->opaque, pStream->state);
- pStream->state = NULL;
- }
- return MZ_OK;
-}
-
-mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) {
- (void)pStream;
- // This is really over conservative. (And lame, but it's actually pretty
- // tricky to compute a true upper bound given the way tdefl's blocking works.)
- return MZ_MAX(128 + (source_len * 110) / 100,
- 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5);
-}
-
-int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len,
- const unsigned char *pSource, mz_ulong source_len, int level) {
- int status;
- mz_stream stream;
- memset(&stream, 0, sizeof(stream));
-
- // In case mz_ulong is 64-bits (argh I hate longs).
- if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR;
-
- stream.next_in = pSource;
- stream.avail_in = (mz_uint32)source_len;
- stream.next_out = pDest;
- stream.avail_out = (mz_uint32)*pDest_len;
-
- status = mz_deflateInit(&stream, level);
- if (status != MZ_OK) return status;
-
- status = mz_deflate(&stream, MZ_FINISH);
- if (status != MZ_STREAM_END) {
- mz_deflateEnd(&stream);
- return (status == MZ_OK) ? MZ_BUF_ERROR : status;
- }
-
- *pDest_len = stream.total_out;
- return mz_deflateEnd(&stream);
-}
-
-int mz_compress(unsigned char *pDest, mz_ulong *pDest_len,
- const unsigned char *pSource, mz_ulong source_len) {
- return mz_compress2(pDest, pDest_len, pSource, source_len,
- MZ_DEFAULT_COMPRESSION);
-}
-
-mz_ulong mz_compressBound(mz_ulong source_len) {
- return mz_deflateBound(NULL, source_len);
-}
-
-typedef struct {
- tinfl_decompressor m_decomp;
- mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed;
- int m_window_bits;
- mz_uint8 m_dict[TINFL_LZ_DICT_SIZE];
- tinfl_status m_last_status;
-} inflate_state;
-
-int mz_inflateInit2(mz_streamp pStream, int window_bits) {
- inflate_state *pDecomp;
- if (!pStream) return MZ_STREAM_ERROR;
- if ((window_bits != MZ_DEFAULT_WINDOW_BITS) &&
- (-window_bits != MZ_DEFAULT_WINDOW_BITS))
- return MZ_PARAM_ERROR;
-
- pStream->data_type = 0;
- pStream->adler = 0;
- pStream->msg = NULL;
- pStream->total_in = 0;
- pStream->total_out = 0;
- pStream->reserved = 0;
- if (!pStream->zalloc) pStream->zalloc = def_alloc_func;
- if (!pStream->zfree) pStream->zfree = def_free_func;
-
- pDecomp = (inflate_state *)pStream->zalloc(pStream->opaque, 1,
- sizeof(inflate_state));
- if (!pDecomp) return MZ_MEM_ERROR;
-
- pStream->state = (struct mz_internal_state *)pDecomp;
-
- tinfl_init(&pDecomp->m_decomp);
- pDecomp->m_dict_ofs = 0;
- pDecomp->m_dict_avail = 0;
- pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT;
- pDecomp->m_first_call = 1;
- pDecomp->m_has_flushed = 0;
- pDecomp->m_window_bits = window_bits;
-
- return MZ_OK;
-}
-
-int mz_inflateInit(mz_streamp pStream) {
- return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS);
-}
-
-int mz_inflate(mz_streamp pStream, int flush) {
- inflate_state *pState;
- mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32;
- size_t in_bytes, out_bytes, orig_avail_in;
- tinfl_status status;
-
- if ((!pStream) || (!pStream->state)) return MZ_STREAM_ERROR;
- if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH;
- if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH))
- return MZ_STREAM_ERROR;
-
- pState = (inflate_state *)pStream->state;
- if (pState->m_window_bits > 0) decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER;
- orig_avail_in = pStream->avail_in;
-
- first_call = pState->m_first_call;
- pState->m_first_call = 0;
- if (pState->m_last_status < 0) return MZ_DATA_ERROR;
-
- if (pState->m_has_flushed && (flush != MZ_FINISH)) return MZ_STREAM_ERROR;
- pState->m_has_flushed |= (flush == MZ_FINISH);
-
- if ((flush == MZ_FINISH) && (first_call)) {
- // MZ_FINISH on the first call implies that the input and output buffers are
- // large enough to hold the entire compressed/decompressed file.
- decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF;
- in_bytes = pStream->avail_in;
- out_bytes = pStream->avail_out;
- status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes,
- pStream->next_out, pStream->next_out, &out_bytes,
- decomp_flags);
- pState->m_last_status = status;
- pStream->next_in += (mz_uint)in_bytes;
- pStream->avail_in -= (mz_uint)in_bytes;
- pStream->total_in += (mz_uint)in_bytes;
- pStream->adler = tinfl_get_adler32(&pState->m_decomp);
- pStream->next_out += (mz_uint)out_bytes;
- pStream->avail_out -= (mz_uint)out_bytes;
- pStream->total_out += (mz_uint)out_bytes;
-
- if (status < 0)
- return MZ_DATA_ERROR;
- else if (status != TINFL_STATUS_DONE) {
- pState->m_last_status = TINFL_STATUS_FAILED;
- return MZ_BUF_ERROR;
- }
- return MZ_STREAM_END;
- }
- // flush != MZ_FINISH then we must assume there's more input.
- if (flush != MZ_FINISH) decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT;
-
- if (pState->m_dict_avail) {
- n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
- memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
- pStream->next_out += n;
- pStream->avail_out -= n;
- pStream->total_out += n;
- pState->m_dict_avail -= n;
- pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
- return ((pState->m_last_status == TINFL_STATUS_DONE) &&
- (!pState->m_dict_avail))
- ? MZ_STREAM_END
- : MZ_OK;
- }
-
- for (;;) {
- in_bytes = pStream->avail_in;
- out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs;
-
- status = tinfl_decompress(
- &pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict,
- pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags);
- pState->m_last_status = status;
-
- pStream->next_in += (mz_uint)in_bytes;
- pStream->avail_in -= (mz_uint)in_bytes;
- pStream->total_in += (mz_uint)in_bytes;
- pStream->adler = tinfl_get_adler32(&pState->m_decomp);
-
- pState->m_dict_avail = (mz_uint)out_bytes;
-
- n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
- memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
- pStream->next_out += n;
- pStream->avail_out -= n;
- pStream->total_out += n;
- pState->m_dict_avail -= n;
- pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
-
- if (status < 0)
- return MZ_DATA_ERROR; // Stream is corrupted (there could be some
- // uncompressed data left in the output dictionary -
- // oh well).
- else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in))
- return MZ_BUF_ERROR; // Signal caller that we can't make forward progress
- // without supplying more input or by setting flush
- // to MZ_FINISH.
- else if (flush == MZ_FINISH) {
- // The output buffer MUST be large to hold the remaining uncompressed data
- // when flush==MZ_FINISH.
- if (status == TINFL_STATUS_DONE)
- return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END;
- // status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's
- // at least 1 more byte on the way. If there's no more room left in the
- // output buffer then something is wrong.
- else if (!pStream->avail_out)
- return MZ_BUF_ERROR;
- } else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) ||
- (!pStream->avail_out) || (pState->m_dict_avail))
- break;
- }
-
- return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail))
- ? MZ_STREAM_END
- : MZ_OK;
-}
-
-int mz_inflateEnd(mz_streamp pStream) {
- if (!pStream) return MZ_STREAM_ERROR;
- if (pStream->state) {
- pStream->zfree(pStream->opaque, pStream->state);
- pStream->state = NULL;
- }
- return MZ_OK;
-}
-
-int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len,
- const unsigned char *pSource, mz_ulong source_len) {
- mz_stream stream;
- int status;
- memset(&stream, 0, sizeof(stream));
-
- // In case mz_ulong is 64-bits (argh I hate longs).
- if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR;
-
- stream.next_in = pSource;
- stream.avail_in = (mz_uint32)source_len;
- stream.next_out = pDest;
- stream.avail_out = (mz_uint32)*pDest_len;
-
- status = mz_inflateInit(&stream);
- if (status != MZ_OK) return status;
-
- status = mz_inflate(&stream, MZ_FINISH);
- if (status != MZ_STREAM_END) {
- mz_inflateEnd(&stream);
- return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR
- : status;
- }
- *pDest_len = stream.total_out;
-
- return mz_inflateEnd(&stream);
-}
-
-const char *mz_error(int err) {
- static struct {
- int m_err;
- const char *m_pDesc;
- } s_error_descs[] = {{MZ_OK, ""},
- {MZ_STREAM_END, "stream end"},
- {MZ_NEED_DICT, "need dictionary"},
- {MZ_ERRNO, "file error"},
- {MZ_STREAM_ERROR, "stream error"},
- {MZ_DATA_ERROR, "data error"},
- {MZ_MEM_ERROR, "out of memory"},
- {MZ_BUF_ERROR, "buf error"},
- {MZ_VERSION_ERROR, "version error"},
- {MZ_PARAM_ERROR, "parameter error"}};
- mz_uint i;
- for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i)
- if (s_error_descs[i].m_err == err) return s_error_descs[i].m_pDesc;
- return NULL;
-}
-
-#endif // MINIZ_NO_ZLIB_APIS
-
-// ------------------- Low-level Decompression (completely independent from all
-// compression API's)
-
-#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l)
-#define TINFL_MEMSET(p, c, l) memset(p, c, l)
-
-#define TINFL_CR_BEGIN \
- switch (r->m_state) { \
- case 0:
-#define TINFL_CR_RETURN(state_index, result) \
- do { \
- status = result; \
- r->m_state = state_index; \
- goto common_exit; \
- case state_index:; \
- } \
- MZ_MACRO_END
-#define TINFL_CR_RETURN_FOREVER(state_index, result) \
- do { \
- for (;;) { \
- TINFL_CR_RETURN(state_index, result); \
- } \
- } \
- MZ_MACRO_END
-#define TINFL_CR_FINISH }
-
-// TODO: If the caller has indicated that there's no more input, and we attempt
-// to read beyond the input buf, then something is wrong with the input because
-// the inflator never
-// reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of
-// the stream with 0's in this scenario.
-#define TINFL_GET_BYTE(state_index, c) \
- do { \
- if (pIn_buf_cur >= pIn_buf_end) { \
- for (;;) { \
- if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \
- TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \
- if (pIn_buf_cur < pIn_buf_end) { \
- c = *pIn_buf_cur++; \
- break; \
- } \
- } else { \
- c = 0; \
- break; \
- } \
- } \
- } else \
- c = *pIn_buf_cur++; \
- } \
- MZ_MACRO_END
-
-#define TINFL_NEED_BITS(state_index, n) \
- do { \
- mz_uint c; \
- TINFL_GET_BYTE(state_index, c); \
- bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \
- num_bits += 8; \
- } while (num_bits < (mz_uint)(n))
-#define TINFL_SKIP_BITS(state_index, n) \
- do { \
- if (num_bits < (mz_uint)(n)) { \
- TINFL_NEED_BITS(state_index, n); \
- } \
- bit_buf >>= (n); \
- num_bits -= (n); \
- } \
- MZ_MACRO_END
-#define TINFL_GET_BITS(state_index, b, n) \
- do { \
- if (num_bits < (mz_uint)(n)) { \
- TINFL_NEED_BITS(state_index, n); \
- } \
- b = bit_buf & ((1 << (n)) - 1); \
- bit_buf >>= (n); \
- num_bits -= (n); \
- } \
- MZ_MACRO_END
-
-// TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes
-// remaining in the input buffer falls below 2.
-// It reads just enough bytes from the input stream that are needed to decode
-// the next Huffman code (and absolutely no more). It works by trying to fully
-// decode a
-// Huffman code by using whatever bits are currently present in the bit buffer.
-// If this fails, it reads another byte, and tries again until it succeeds or
-// until the
-// bit buffer contains >=15 bits (deflate's max. Huffman code size).
-#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \
- do { \
- temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \
- if (temp >= 0) { \
- code_len = temp >> 9; \
- if ((code_len) && (num_bits >= code_len)) break; \
- } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \
- code_len = TINFL_FAST_LOOKUP_BITS; \
- do { \
- temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \
- } while ((temp < 0) && (num_bits >= (code_len + 1))); \
- if (temp >= 0) break; \
- } \
- TINFL_GET_BYTE(state_index, c); \
- bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \
- num_bits += 8; \
- } while (num_bits < 15);
-
-// TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex
-// than you would initially expect because the zlib API expects the decompressor
-// to never read
-// beyond the final byte of the deflate stream. (In other words, when this macro
-// wants to read another byte from the input, it REALLY needs another byte in
-// order to fully
-// decode the next Huffman code.) Handling this properly is particularly
-// important on raw deflate (non-zlib) streams, which aren't followed by a byte
-// aligned adler-32.
-// The slow path is only executed at the very end of the input buffer.
-#define TINFL_HUFF_DECODE(state_index, sym, pHuff) \
- do { \
- int temp; \
- mz_uint code_len, c; \
- if (num_bits < 15) { \
- if ((pIn_buf_end - pIn_buf_cur) < 2) { \
- TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \
- } else { \
- bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | \
- (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); \
- pIn_buf_cur += 2; \
- num_bits += 16; \
- } \
- } \
- if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= \
- 0) \
- code_len = temp >> 9, temp &= 511; \
- else { \
- code_len = TINFL_FAST_LOOKUP_BITS; \
- do { \
- temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \
- } while (temp < 0); \
- } \
- sym = temp; \
- bit_buf >>= code_len; \
- num_bits -= code_len; \
- } \
- MZ_MACRO_END
-
-tinfl_status tinfl_decompress(tinfl_decompressor *r,
- const mz_uint8 *pIn_buf_next,
- size_t *pIn_buf_size, mz_uint8 *pOut_buf_start,
- mz_uint8 *pOut_buf_next, size_t *pOut_buf_size,
- const mz_uint32 decomp_flags) {
- static const int s_length_base[31] = {
- 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
- 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
- static const int s_length_extra[31] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
- 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4,
- 4, 4, 5, 5, 5, 5, 0, 0, 0};
- static const int s_dist_base[32] = {
- 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33,
- 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537,
- 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0};
- static const int s_dist_extra[32] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3,
- 4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
- 9, 9, 10, 10, 11, 11, 12, 12, 13, 13};
- static const mz_uint8 s_length_dezigzag[19] = {
- 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
- static const int s_min_table_sizes[3] = {257, 1, 4};
-
- tinfl_status status = TINFL_STATUS_FAILED;
- mz_uint32 num_bits, dist, counter, num_extra;
- tinfl_bit_buf_t bit_buf;
- const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end =
- pIn_buf_next + *pIn_buf_size;
- mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end =
- pOut_buf_next + *pOut_buf_size;
- size_t out_buf_size_mask =
- (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)
- ? (size_t)-1
- : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1,
- dist_from_out_buf_start;
-
- // Ensure the output buffer's size is a power of 2, unless the output buffer
- // is large enough to hold the entire output file (in which case it doesn't
- // matter).
- if (((out_buf_size_mask + 1) & out_buf_size_mask) ||
- (pOut_buf_next < pOut_buf_start)) {
- *pIn_buf_size = *pOut_buf_size = 0;
- return TINFL_STATUS_BAD_PARAM;
- }
-
- num_bits = r->m_num_bits;
- bit_buf = r->m_bit_buf;
- dist = r->m_dist;
- counter = r->m_counter;
- num_extra = r->m_num_extra;
- dist_from_out_buf_start = r->m_dist_from_out_buf_start;
- TINFL_CR_BEGIN
-
- bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0;
- r->m_z_adler32 = r->m_check_adler32 = 1;
- if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) {
- TINFL_GET_BYTE(1, r->m_zhdr0);
- TINFL_GET_BYTE(2, r->m_zhdr1);
- counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) ||
- (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8));
- if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))
- counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) ||
- ((out_buf_size_mask + 1) <
- (size_t)(1ULL << (8U + (r->m_zhdr0 >> 4)))));
- if (counter) {
- TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED);
- }
- }
-
- do {
- TINFL_GET_BITS(3, r->m_final, 3);
- r->m_type = r->m_final >> 1;
- if (r->m_type == 0) {
- TINFL_SKIP_BITS(5, num_bits & 7);
- for (counter = 0; counter < 4; ++counter) {
- if (num_bits)
- TINFL_GET_BITS(6, r->m_raw_header[counter], 8);
- else
- TINFL_GET_BYTE(7, r->m_raw_header[counter]);
- }
- if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) !=
- (mz_uint)(0xFFFF ^
- (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) {
- TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED);
- }
- while ((counter) && (num_bits)) {
- TINFL_GET_BITS(51, dist, 8);
- while (pOut_buf_cur >= pOut_buf_end) {
- TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT);
- }
- *pOut_buf_cur++ = (mz_uint8)dist;
- counter--;
- }
- while (counter) {
- size_t n;
- while (pOut_buf_cur >= pOut_buf_end) {
- TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT);
- }
- while (pIn_buf_cur >= pIn_buf_end) {
- if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) {
- TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT);
- } else {
- TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED);
- }
- }
- n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur),
- (size_t)(pIn_buf_end - pIn_buf_cur)),
- counter);
- TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n);
- pIn_buf_cur += n;
- pOut_buf_cur += n;
- counter -= (mz_uint)n;
- }
- } else if (r->m_type == 3) {
- TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED);
- } else {
- if (r->m_type == 1) {
- mz_uint8 *p = r->m_tables[0].m_code_size;
- mz_uint i;
- r->m_table_sizes[0] = 288;
- r->m_table_sizes[1] = 32;
- TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32);
- for (i = 0; i <= 143; ++i) *p++ = 8;
- for (; i <= 255; ++i) *p++ = 9;
- for (; i <= 279; ++i) *p++ = 7;
- for (; i <= 287; ++i) *p++ = 8;
- } else {
- for (counter = 0; counter < 3; counter++) {
- TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]);
- r->m_table_sizes[counter] += s_min_table_sizes[counter];
- }
- MZ_CLEAR_OBJ(r->m_tables[2].m_code_size);
- for (counter = 0; counter < r->m_table_sizes[2]; counter++) {
- mz_uint s;
- TINFL_GET_BITS(14, s, 3);
- r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s;
- }
- r->m_table_sizes[2] = 19;
- }
- for (; (int)r->m_type >= 0; r->m_type--) {
- int tree_next, tree_cur;
- tinfl_huff_table *pTable;
- mz_uint i, j, used_syms, total, sym_index, next_code[17],
- total_syms[16];
- pTable = &r->m_tables[r->m_type];
- MZ_CLEAR_OBJ(total_syms);
- MZ_CLEAR_OBJ(pTable->m_look_up);
- MZ_CLEAR_OBJ(pTable->m_tree);
- for (i = 0; i < r->m_table_sizes[r->m_type]; ++i)
- total_syms[pTable->m_code_size[i]]++;
- used_syms = 0, total = 0;
- next_code[0] = next_code[1] = 0;
- for (i = 1; i <= 15; ++i) {
- used_syms += total_syms[i];
- next_code[i + 1] = (total = ((total + total_syms[i]) << 1));
- }
- if ((65536 != total) && (used_syms > 1)) {
- TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED);
- }
- for (tree_next = -1, sym_index = 0;
- sym_index < r->m_table_sizes[r->m_type]; ++sym_index) {
- mz_uint rev_code = 0, l, cur_code,
- code_size = pTable->m_code_size[sym_index];
- if (!code_size) continue;
- cur_code = next_code[code_size]++;
- for (l = code_size; l > 0; l--, cur_code >>= 1)
- rev_code = (rev_code << 1) | (cur_code & 1);
- if (code_size <= TINFL_FAST_LOOKUP_BITS) {
- mz_int16 k = (mz_int16)((code_size << 9) | sym_index);
- while (rev_code < TINFL_FAST_LOOKUP_SIZE) {
- pTable->m_look_up[rev_code] = k;
- rev_code += (1 << code_size);
- }
- continue;
- }
- if (0 ==
- (tree_cur = pTable->m_look_up[rev_code &
- (TINFL_FAST_LOOKUP_SIZE - 1)])) {
- pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] =
- (mz_int16)tree_next;
- tree_cur = tree_next;
- tree_next -= 2;
- }
- rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1);
- for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) {
- tree_cur -= ((rev_code >>= 1) & 1);
- if (!pTable->m_tree[-tree_cur - 1]) {
- pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next;
- tree_cur = tree_next;
- tree_next -= 2;
- } else
- tree_cur = pTable->m_tree[-tree_cur - 1];
- }
- tree_cur -= ((rev_code >>= 1) & 1);
- pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index;
- }
- if (r->m_type == 2) {
- for (counter = 0;
- counter < (r->m_table_sizes[0] + r->m_table_sizes[1]);) {
- mz_uint s;
- TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]);
- if (dist < 16) {
- r->m_len_codes[counter++] = (mz_uint8)dist;
- continue;
- }
- if ((dist == 16) && (!counter)) {
- TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED);
- }
- num_extra = "\02\03\07"[dist - 16];
- TINFL_GET_BITS(18, s, num_extra);
- s += "\03\03\013"[dist - 16];
- TINFL_MEMSET(r->m_len_codes + counter,
- (dist == 16) ? r->m_len_codes[counter - 1] : 0, s);
- counter += s;
- }
- if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) {
- TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED);
- }
- TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes,
- r->m_table_sizes[0]);
- TINFL_MEMCPY(r->m_tables[1].m_code_size,
- r->m_len_codes + r->m_table_sizes[0],
- r->m_table_sizes[1]);
- }
- }
- for (;;) {
- mz_uint8 *pSrc;
- for (;;) {
- if (((pIn_buf_end - pIn_buf_cur) < 4) ||
- ((pOut_buf_end - pOut_buf_cur) < 2)) {
- TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]);
- if (counter >= 256) break;
- while (pOut_buf_cur >= pOut_buf_end) {
- TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT);
- }
- *pOut_buf_cur++ = (mz_uint8)counter;
- } else {
- int sym2;
- mz_uint code_len;
-#if TINFL_USE_64BIT_BITBUF
- if (num_bits < 30) {
- bit_buf |=
- (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits);
- pIn_buf_cur += 4;
- num_bits += 32;
- }
-#else
- if (num_bits < 15) {
- bit_buf |=
- (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits);
- pIn_buf_cur += 2;
- num_bits += 16;
- }
-#endif
- if ((sym2 =
- r->m_tables[0]
- .m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >=
- 0)
- code_len = sym2 >> 9;
- else {
- code_len = TINFL_FAST_LOOKUP_BITS;
- do {
- sym2 = r->m_tables[0]
- .m_tree[~sym2 + ((bit_buf >> code_len++) & 1)];
- } while (sym2 < 0);
- }
- counter = sym2;
- bit_buf >>= code_len;
- num_bits -= code_len;
- if (counter & 256) break;
-
-#if !TINFL_USE_64BIT_BITBUF
- if (num_bits < 15) {
- bit_buf |=
- (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits);
- pIn_buf_cur += 2;
- num_bits += 16;
- }
-#endif
- if ((sym2 =
- r->m_tables[0]
- .m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >=
- 0)
- code_len = sym2 >> 9;
- else {
- code_len = TINFL_FAST_LOOKUP_BITS;
- do {
- sym2 = r->m_tables[0]
- .m_tree[~sym2 + ((bit_buf >> code_len++) & 1)];
- } while (sym2 < 0);
- }
- bit_buf >>= code_len;
- num_bits -= code_len;
-
- pOut_buf_cur[0] = (mz_uint8)counter;
- if (sym2 & 256) {
- pOut_buf_cur++;
- counter = sym2;
- break;
- }
- pOut_buf_cur[1] = (mz_uint8)sym2;
- pOut_buf_cur += 2;
- }
- }
- if ((counter &= 511) == 256) break;
-
- num_extra = s_length_extra[counter - 257];
- counter = s_length_base[counter - 257];
- if (num_extra) {
- mz_uint extra_bits;
- TINFL_GET_BITS(25, extra_bits, num_extra);
- counter += extra_bits;
- }
-
- TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]);
- num_extra = s_dist_extra[dist];
- dist = s_dist_base[dist];
- if (num_extra) {
- mz_uint extra_bits;
- TINFL_GET_BITS(27, extra_bits, num_extra);
- dist += extra_bits;
- }
-
- dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start;
- if ((dist > dist_from_out_buf_start) &&
- (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) {
- TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED);
- }
-
- pSrc = pOut_buf_start +
- ((dist_from_out_buf_start - dist) & out_buf_size_mask);
-
- if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) {
- while (counter--) {
- while (pOut_buf_cur >= pOut_buf_end) {
- TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT);
- }
- *pOut_buf_cur++ =
- pOut_buf_start[(dist_from_out_buf_start++ - dist) &
- out_buf_size_mask];
- }
- continue;
- }
-#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
- else if ((counter >= 9) && (counter <= dist)) {
- const mz_uint8 *pSrc_end = pSrc + (counter & ~7);
- do {
- ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0];
- ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1];
- pOut_buf_cur += 8;
- } while ((pSrc += 8) < pSrc_end);
- if ((counter &= 7) < 3) {
- if (counter) {
- pOut_buf_cur[0] = pSrc[0];
- if (counter > 1) pOut_buf_cur[1] = pSrc[1];
- pOut_buf_cur += counter;
- }
- continue;
- }
- }
-#endif
- do {
- pOut_buf_cur[0] = pSrc[0];
- pOut_buf_cur[1] = pSrc[1];
- pOut_buf_cur[2] = pSrc[2];
- pOut_buf_cur += 3;
- pSrc += 3;
- } while ((int)(counter -= 3) > 2);
- if ((int)counter > 0) {
- pOut_buf_cur[0] = pSrc[0];
- if ((int)counter > 1) pOut_buf_cur[1] = pSrc[1];
- pOut_buf_cur += counter;
- }
- }
- }
- } while (!(r->m_final & 1));
- if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) {
- TINFL_SKIP_BITS(32, num_bits & 7);
- for (counter = 0; counter < 4; ++counter) {
- mz_uint s;
- if (num_bits)
- TINFL_GET_BITS(41, s, 8);
- else
- TINFL_GET_BYTE(42, s);
- r->m_z_adler32 = (r->m_z_adler32 << 8) | s;
- }
- }
- TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE);
- TINFL_CR_FINISH
-
-common_exit:
- r->m_num_bits = num_bits;
- r->m_bit_buf = bit_buf;
- r->m_dist = dist;
- r->m_counter = counter;
- r->m_num_extra = num_extra;
- r->m_dist_from_out_buf_start = dist_from_out_buf_start;
- *pIn_buf_size = pIn_buf_cur - pIn_buf_next;
- *pOut_buf_size = pOut_buf_cur - pOut_buf_next;
- if ((decomp_flags &
- (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) &&
- (status >= 0)) {
- const mz_uint8 *ptr = pOut_buf_next;
- size_t buf_len = *pOut_buf_size;
- mz_uint32 i, s1 = r->m_check_adler32 & 0xffff,
- s2 = r->m_check_adler32 >> 16;
- size_t block_len = buf_len % 5552;
- while (buf_len) {
- for (i = 0; i + 7 < block_len; i += 8, ptr += 8) {
- s1 += ptr[0], s2 += s1;
- s1 += ptr[1], s2 += s1;
- s1 += ptr[2], s2 += s1;
- s1 += ptr[3], s2 += s1;
- s1 += ptr[4], s2 += s1;
- s1 += ptr[5], s2 += s1;
- s1 += ptr[6], s2 += s1;
- s1 += ptr[7], s2 += s1;
- }
- for (; i < block_len; ++i) s1 += *ptr++, s2 += s1;
- s1 %= 65521U, s2 %= 65521U;
- buf_len -= block_len;
- block_len = 5552;
- }
- r->m_check_adler32 = (s2 << 16) + s1;
- if ((status == TINFL_STATUS_DONE) &&
- (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) &&
- (r->m_check_adler32 != r->m_z_adler32))
- status = TINFL_STATUS_ADLER32_MISMATCH;
- }
- return status;
-}
-
-// Higher level helper functions.
-void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len,
- size_t *pOut_len, int flags) {
- tinfl_decompressor decomp;
- void *pBuf = NULL, *pNew_buf;
- size_t src_buf_ofs = 0, out_buf_capacity = 0;
- *pOut_len = 0;
- tinfl_init(&decomp);
- for (;;) {
- size_t src_buf_size = src_buf_len - src_buf_ofs,
- dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity;
- tinfl_status status = tinfl_decompress(
- &decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size,
- (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL,
- &dst_buf_size,
- (flags & ~TINFL_FLAG_HAS_MORE_INPUT) |
- TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
- if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) {
- MZ_FREE(pBuf);
- *pOut_len = 0;
- return NULL;
- }
- src_buf_ofs += src_buf_size;
- *pOut_len += dst_buf_size;
- if (status == TINFL_STATUS_DONE) break;
- new_out_buf_capacity = out_buf_capacity * 2;
- if (new_out_buf_capacity < 128) new_out_buf_capacity = 128;
- pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity);
- if (!pNew_buf) {
- MZ_FREE(pBuf);
- *pOut_len = 0;
- return NULL;
- }
- pBuf = pNew_buf;
- out_buf_capacity = new_out_buf_capacity;
- }
- return pBuf;
-}
-
-size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len,
- const void *pSrc_buf, size_t src_buf_len,
- int flags) {
- tinfl_decompressor decomp;
- tinfl_status status;
- tinfl_init(&decomp);
- status =
- tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len,
- (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len,
- (flags & ~TINFL_FLAG_HAS_MORE_INPUT) |
- TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
- return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED
- : out_buf_len;
-}
-
-int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size,
- tinfl_put_buf_func_ptr pPut_buf_func,
- void *pPut_buf_user, int flags) {
- int result = 0;
- tinfl_decompressor decomp;
- mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE);
- size_t in_buf_ofs = 0, dict_ofs = 0;
- if (!pDict) return TINFL_STATUS_FAILED;
- tinfl_init(&decomp);
- for (;;) {
- size_t in_buf_size = *pIn_buf_size - in_buf_ofs,
- dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs;
- tinfl_status status =
- tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs,
- &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size,
- (flags & ~(TINFL_FLAG_HAS_MORE_INPUT |
- TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)));
- in_buf_ofs += in_buf_size;
- if ((dst_buf_size) &&
- (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user)))
- break;
- if (status != TINFL_STATUS_HAS_MORE_OUTPUT) {
- result = (status == TINFL_STATUS_DONE);
- break;
- }
- dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1);
- }
- MZ_FREE(pDict);
- *pIn_buf_size = in_buf_ofs;
- return result;
-}
-
-// ------------------- Low-level Compression (independent from all decompression
-// API's)
-
-// Purposely making these tables static for faster init and thread safety.
-static const mz_uint16 s_tdefl_len_sym[256] = {
- 257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268,
- 268, 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272,
- 272, 272, 273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274,
- 274, 274, 274, 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276,
- 276, 276, 276, 276, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
- 277, 277, 277, 277, 277, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
- 278, 278, 278, 278, 278, 278, 279, 279, 279, 279, 279, 279, 279, 279, 279,
- 279, 279, 279, 279, 279, 279, 279, 280, 280, 280, 280, 280, 280, 280, 280,
- 280, 280, 280, 280, 280, 280, 280, 280, 281, 281, 281, 281, 281, 281, 281,
- 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281,
- 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 282, 282, 282, 282, 282,
- 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282,
- 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 283, 283, 283,
- 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283,
- 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 284,
- 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284,
- 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284,
- 285};
-
-static const mz_uint8 s_tdefl_len_extra[256] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0};
-
-static const mz_uint8 s_tdefl_small_dist_sym[512] = {
- 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8,
- 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10,
- 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11,
- 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14,
- 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
- 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
- 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
- 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17};
-
-static const mz_uint8 s_tdefl_small_dist_extra[512] = {
- 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7};
-
-static const mz_uint8 s_tdefl_large_dist_sym[128] = {
- 0, 0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24,
- 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27,
- 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
- 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
- 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
- 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29};
-
-static const mz_uint8 s_tdefl_large_dist_extra[128] = {
- 0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11,
- 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13};
-
-// Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted
-// values.
-typedef struct {
- mz_uint16 m_key, m_sym_index;
-} tdefl_sym_freq;
-static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms,
- tdefl_sym_freq *pSyms0,
- tdefl_sym_freq *pSyms1) {
- mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2];
- tdefl_sym_freq *pCur_syms = pSyms0, *pNew_syms = pSyms1;
- MZ_CLEAR_OBJ(hist);
- for (i = 0; i < num_syms; i++) {
- mz_uint freq = pSyms0[i].m_key;
- hist[freq & 0xFF]++;
- hist[256 + ((freq >> 8) & 0xFF)]++;
- }
- while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256]))
- total_passes--;
- for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) {
- const mz_uint32 *pHist = &hist[pass << 8];
- mz_uint offsets[256], cur_ofs = 0;
- for (i = 0; i < 256; i++) {
- offsets[i] = cur_ofs;
- cur_ofs += pHist[i];
- }
- for (i = 0; i < num_syms; i++)
- pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] =
- pCur_syms[i];
- {
- tdefl_sym_freq *t = pCur_syms;
- pCur_syms = pNew_syms;
- pNew_syms = t;
- }
- }
- return pCur_syms;
-}
-
-// tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat,
-// alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996.
-static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) {
- int root, leaf, next, avbl, used, dpth;
- if (n == 0)
- return;
- else if (n == 1) {
- A[0].m_key = 1;
- return;
- }
- A[0].m_key += A[1].m_key;
- root = 0;
- leaf = 2;
- for (next = 1; next < n - 1; next++) {
- if (leaf >= n || A[root].m_key < A[leaf].m_key) {
- A[next].m_key = A[root].m_key;
- A[root++].m_key = (mz_uint16)next;
- } else
- A[next].m_key = A[leaf++].m_key;
- if (leaf >= n || (root < next && A[root].m_key < A[leaf].m_key)) {
- A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key);
- A[root++].m_key = (mz_uint16)next;
- } else
- A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key);
- }
- A[n - 2].m_key = 0;
- for (next = n - 3; next >= 0; next--)
- A[next].m_key = A[A[next].m_key].m_key + 1;
- avbl = 1;
- used = dpth = 0;
- root = n - 2;
- next = n - 1;
- while (avbl > 0) {
- while (root >= 0 && (int)A[root].m_key == dpth) {
- used++;
- root--;
- }
- while (avbl > used) {
- A[next--].m_key = (mz_uint16)(dpth);
- avbl--;
- }
- avbl = 2 * used;
- dpth++;
- used = 0;
- }
-}
-
-// Limits canonical Huffman code table's max code size.
-enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 };
-static void tdefl_huffman_enforce_max_code_size(int *pNum_codes,
- int code_list_len,
- int max_code_size) {
- int i;
- mz_uint32 total = 0;
- if (code_list_len <= 1) return;
- for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++)
- pNum_codes[max_code_size] += pNum_codes[i];
- for (i = max_code_size; i > 0; i--)
- total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i));
- while (total != (1UL << max_code_size)) {
- pNum_codes[max_code_size]--;
- for (i = max_code_size - 1; i > 0; i--)
- if (pNum_codes[i]) {
- pNum_codes[i]--;
- pNum_codes[i + 1] += 2;
- break;
- }
- total--;
- }
-}
-
-static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num,
- int table_len, int code_size_limit,
- int static_table) {
- int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE];
- mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1];
- MZ_CLEAR_OBJ(num_codes);
- if (static_table) {
- for (i = 0; i < table_len; i++)
- num_codes[d->m_huff_code_sizes[table_num][i]]++;
- } else {
- tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS],
- *pSyms;
- int num_used_syms = 0;
- const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0];
- for (i = 0; i < table_len; i++)
- if (pSym_count[i]) {
- syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i];
- syms0[num_used_syms++].m_sym_index = (mz_uint16)i;
- }
-
- pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1);
- tdefl_calculate_minimum_redundancy(pSyms, num_used_syms);
-
- for (i = 0; i < num_used_syms; i++) num_codes[pSyms[i].m_key]++;
-
- tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms,
- code_size_limit);
-
- MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]);
- MZ_CLEAR_OBJ(d->m_huff_codes[table_num]);
- for (i = 1, j = num_used_syms; i <= code_size_limit; i++)
- for (l = num_codes[i]; l > 0; l--)
- d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i);
- }
-
- next_code[1] = 0;
- for (j = 0, i = 2; i <= code_size_limit; i++)
- next_code[i] = j = ((j + num_codes[i - 1]) << 1);
-
- for (i = 0; i < table_len; i++) {
- mz_uint rev_code = 0, code, code_size;
- if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) continue;
- code = next_code[code_size]++;
- for (l = code_size; l > 0; l--, code >>= 1)
- rev_code = (rev_code << 1) | (code & 1);
- d->m_huff_codes[table_num][i] = (mz_uint16)rev_code;
- }
-}
-
-#define TDEFL_PUT_BITS(b, l) \
- do { \
- mz_uint bits = b; \
- mz_uint len = l; \
- MZ_ASSERT(bits <= ((1U << len) - 1U)); \
- d->m_bit_buffer |= (bits << d->m_bits_in); \
- d->m_bits_in += len; \
- while (d->m_bits_in >= 8) { \
- if (d->m_pOutput_buf < d->m_pOutput_buf_end) \
- *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \
- d->m_bit_buffer >>= 8; \
- d->m_bits_in -= 8; \
- } \
- } \
- MZ_MACRO_END
-
-#define TDEFL_RLE_PREV_CODE_SIZE() \
- { \
- if (rle_repeat_count) { \
- if (rle_repeat_count < 3) { \
- d->m_huff_count[2][prev_code_size] = (mz_uint16)( \
- d->m_huff_count[2][prev_code_size] + rle_repeat_count); \
- while (rle_repeat_count--) \
- packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \
- } else { \
- d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); \
- packed_code_sizes[num_packed_code_sizes++] = 16; \
- packed_code_sizes[num_packed_code_sizes++] = \
- (mz_uint8)(rle_repeat_count - 3); \
- } \
- rle_repeat_count = 0; \
- } \
- }
-
-#define TDEFL_RLE_ZERO_CODE_SIZE() \
- { \
- if (rle_z_count) { \
- if (rle_z_count < 3) { \
- d->m_huff_count[2][0] = \
- (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); \
- while (rle_z_count--) packed_code_sizes[num_packed_code_sizes++] = 0; \
- } else if (rle_z_count <= 10) { \
- d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); \
- packed_code_sizes[num_packed_code_sizes++] = 17; \
- packed_code_sizes[num_packed_code_sizes++] = \
- (mz_uint8)(rle_z_count - 3); \
- } else { \
- d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); \
- packed_code_sizes[num_packed_code_sizes++] = 18; \
- packed_code_sizes[num_packed_code_sizes++] = \
- (mz_uint8)(rle_z_count - 11); \
- } \
- rle_z_count = 0; \
- } \
- }
-
-static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = {
- 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
-
-static void tdefl_start_dynamic_block(tdefl_compressor *d) {
- int num_lit_codes, num_dist_codes, num_bit_lengths;
- mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count,
- rle_repeat_count, packed_code_sizes_index;
- mz_uint8
- code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1],
- packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1],
- prev_code_size = 0xFF;
-
- d->m_huff_count[0][256] = 1;
-
- tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE);
- tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE);
-
- for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--)
- if (d->m_huff_code_sizes[0][num_lit_codes - 1]) break;
- for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--)
- if (d->m_huff_code_sizes[1][num_dist_codes - 1]) break;
-
- memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes);
- memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0],
- num_dist_codes);
- total_code_sizes_to_pack = num_lit_codes + num_dist_codes;
- num_packed_code_sizes = 0;
- rle_z_count = 0;
- rle_repeat_count = 0;
-
- memset(&d->m_huff_count[2][0], 0,
- sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2);
- for (i = 0; i < total_code_sizes_to_pack; i++) {
- mz_uint8 code_size = code_sizes_to_pack[i];
- if (!code_size) {
- TDEFL_RLE_PREV_CODE_SIZE();
- if (++rle_z_count == 138) {
- TDEFL_RLE_ZERO_CODE_SIZE();
- }
- } else {
- TDEFL_RLE_ZERO_CODE_SIZE();
- if (code_size != prev_code_size) {
- TDEFL_RLE_PREV_CODE_SIZE();
- d->m_huff_count[2][code_size] =
- (mz_uint16)(d->m_huff_count[2][code_size] + 1);
- packed_code_sizes[num_packed_code_sizes++] = code_size;
- } else if (++rle_repeat_count == 6) {
- TDEFL_RLE_PREV_CODE_SIZE();
- }
- }
- prev_code_size = code_size;
- }
- if (rle_repeat_count) {
- TDEFL_RLE_PREV_CODE_SIZE();
- } else {
- TDEFL_RLE_ZERO_CODE_SIZE();
- }
-
- tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE);
-
- TDEFL_PUT_BITS(2, 2);
-
- TDEFL_PUT_BITS(num_lit_codes - 257, 5);
- TDEFL_PUT_BITS(num_dist_codes - 1, 5);
-
- for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--)
- if (d->m_huff_code_sizes
- [2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]])
- break;
- num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1));
- TDEFL_PUT_BITS(num_bit_lengths - 4, 4);
- for (i = 0; (int)i < num_bit_lengths; i++)
- TDEFL_PUT_BITS(
- d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3);
-
- for (packed_code_sizes_index = 0;
- packed_code_sizes_index < num_packed_code_sizes;) {
- mz_uint code = packed_code_sizes[packed_code_sizes_index++];
- MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2);
- TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]);
- if (code >= 16)
- TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++],
- "\02\03\07"[code - 16]);
- }
-}
-
-static void tdefl_start_static_block(tdefl_compressor *d) {
- mz_uint i;
- mz_uint8 *p = &d->m_huff_code_sizes[0][0];
-
- for (i = 0; i <= 143; ++i) *p++ = 8;
- for (; i <= 255; ++i) *p++ = 9;
- for (; i <= 279; ++i) *p++ = 7;
- for (; i <= 287; ++i) *p++ = 8;
-
- memset(d->m_huff_code_sizes[1], 5, 32);
-
- tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE);
- tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE);
-
- TDEFL_PUT_BITS(1, 2);
-}
-
-static const mz_uint mz_bitmasks[17] = {
- 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF,
- 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF};
-
-#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && \
- MINIZ_HAS_64BIT_REGISTERS
-static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) {
- mz_uint flags;
- mz_uint8 *pLZ_codes;
- mz_uint8 *pOutput_buf = d->m_pOutput_buf;
- mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf;
- mz_uint64 bit_buffer = d->m_bit_buffer;
- mz_uint bits_in = d->m_bits_in;
-
-#define TDEFL_PUT_BITS_FAST(b, l) \
- { \
- bit_buffer |= (((mz_uint64)(b)) << bits_in); \
- bits_in += (l); \
- }
-
- flags = 1;
- for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end;
- flags >>= 1) {
- if (flags == 1) flags = *pLZ_codes++ | 0x100;
-
- if (flags & 1) {
- mz_uint s0, s1, n0, n1, sym, num_extra_bits;
- mz_uint match_len = pLZ_codes[0],
- match_dist = *(const mz_uint16 *)(pLZ_codes + 1);
- pLZ_codes += 3;
-
- MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
- TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]],
- d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
- TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]],
- s_tdefl_len_extra[match_len]);
-
- // This sequence coaxes MSVC into using cmov's vs. jmp's.
- s0 = s_tdefl_small_dist_sym[match_dist & 511];
- n0 = s_tdefl_small_dist_extra[match_dist & 511];
- s1 = s_tdefl_large_dist_sym[match_dist >> 8];
- n1 = s_tdefl_large_dist_extra[match_dist >> 8];
- sym = (match_dist < 512) ? s0 : s1;
- num_extra_bits = (match_dist < 512) ? n0 : n1;
-
- MZ_ASSERT(d->m_huff_code_sizes[1][sym]);
- TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym],
- d->m_huff_code_sizes[1][sym]);
- TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits],
- num_extra_bits);
- } else {
- mz_uint lit = *pLZ_codes++;
- MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
- TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit],
- d->m_huff_code_sizes[0][lit]);
-
- if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) {
- flags >>= 1;
- lit = *pLZ_codes++;
- MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
- TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit],
- d->m_huff_code_sizes[0][lit]);
-
- if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) {
- flags >>= 1;
- lit = *pLZ_codes++;
- MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
- TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit],
- d->m_huff_code_sizes[0][lit]);
- }
- }
- }
-
- if (pOutput_buf >= d->m_pOutput_buf_end) return MZ_FALSE;
-
- *(mz_uint64 *)pOutput_buf = bit_buffer;
- pOutput_buf += (bits_in >> 3);
- bit_buffer >>= (bits_in & ~7);
- bits_in &= 7;
- }
-
-#undef TDEFL_PUT_BITS_FAST
-
- d->m_pOutput_buf = pOutput_buf;
- d->m_bits_in = 0;
- d->m_bit_buffer = 0;
-
- while (bits_in) {
- mz_uint32 n = MZ_MIN(bits_in, 16);
- TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n);
- bit_buffer >>= n;
- bits_in -= n;
- }
-
- TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]);
-
- return (d->m_pOutput_buf < d->m_pOutput_buf_end);
-}
-#else
-static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) {
- mz_uint flags;
- mz_uint8 *pLZ_codes;
-
- flags = 1;
- for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf;
- flags >>= 1) {
- if (flags == 1) flags = *pLZ_codes++ | 0x100;
- if (flags & 1) {
- mz_uint sym, num_extra_bits;
- mz_uint match_len = pLZ_codes[0],
- match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8));
- pLZ_codes += 3;
-
- MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
- TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]],
- d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
- TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]],
- s_tdefl_len_extra[match_len]);
-
- if (match_dist < 512) {
- sym = s_tdefl_small_dist_sym[match_dist];
- num_extra_bits = s_tdefl_small_dist_extra[match_dist];
- } else {
- sym = s_tdefl_large_dist_sym[match_dist >> 8];
- num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8];
- }
- MZ_ASSERT(d->m_huff_code_sizes[1][sym]);
- TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]);
- TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits);
- } else {
- mz_uint lit = *pLZ_codes++;
- MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
- TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);
- }
- }
-
- TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]);
-
- return (d->m_pOutput_buf < d->m_pOutput_buf_end);
-}
-#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN &&
- // MINIZ_HAS_64BIT_REGISTERS
-
-static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) {
- if (static_block)
- tdefl_start_static_block(d);
- else
- tdefl_start_dynamic_block(d);
- return tdefl_compress_lz_codes(d);
-}
-
-static int tdefl_flush_block(tdefl_compressor *d, int flush) {
- mz_uint saved_bit_buf, saved_bits_in;
- mz_uint8 *pSaved_output_buf;
- mz_bool comp_block_succeeded = MZ_FALSE;
- int n, use_raw_block =
- ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) &&
- (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size;
- mz_uint8 *pOutput_buf_start =
- ((d->m_pPut_buf_func == NULL) &&
- ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE))
- ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs)
- : d->m_output_buf;
-
- d->m_pOutput_buf = pOutput_buf_start;
- d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16;
-
- MZ_ASSERT(!d->m_output_flush_remaining);
- d->m_output_flush_ofs = 0;
- d->m_output_flush_remaining = 0;
-
- *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left);
- d->m_pLZ_code_buf -= (d->m_num_flags_left == 8);
-
- if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) {
- TDEFL_PUT_BITS(0x78, 8);
- TDEFL_PUT_BITS(0x01, 8);
- }
-
- TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1);
-
- pSaved_output_buf = d->m_pOutput_buf;
- saved_bit_buf = d->m_bit_buffer;
- saved_bits_in = d->m_bits_in;
-
- if (!use_raw_block)
- comp_block_succeeded =
- tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) ||
- (d->m_total_lz_bytes < 48));
-
- // If the block gets expanded, forget the current contents of the output
- // buffer and send a raw block instead.
- if (((use_raw_block) ||
- ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >=
- d->m_total_lz_bytes))) &&
- ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size)) {
- mz_uint i;
- d->m_pOutput_buf = pSaved_output_buf;
- d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in;
- TDEFL_PUT_BITS(0, 2);
- if (d->m_bits_in) {
- TDEFL_PUT_BITS(0, 8 - d->m_bits_in);
- }
- for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) {
- TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16);
- }
- for (i = 0; i < d->m_total_lz_bytes; ++i) {
- TDEFL_PUT_BITS(
- d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK],
- 8);
- }
- }
- // Check for the extremely unlikely (if not impossible) case of the compressed
- // block not fitting into the output buffer when using dynamic codes.
- else if (!comp_block_succeeded) {
- d->m_pOutput_buf = pSaved_output_buf;
- d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in;
- tdefl_compress_block(d, MZ_TRUE);
- }
-
- if (flush) {
- if (flush == TDEFL_FINISH) {
- if (d->m_bits_in) {
- TDEFL_PUT_BITS(0, 8 - d->m_bits_in);
- }
- if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) {
- mz_uint i, a = d->m_adler32;
- for (i = 0; i < 4; i++) {
- TDEFL_PUT_BITS((a >> 24) & 0xFF, 8);
- a <<= 8;
- }
- }
- } else {
- mz_uint i, z = 0;
- TDEFL_PUT_BITS(0, 3);
- if (d->m_bits_in) {
- TDEFL_PUT_BITS(0, 8 - d->m_bits_in);
- }
- for (i = 2; i; --i, z ^= 0xFFFF) {
- TDEFL_PUT_BITS(z & 0xFFFF, 16);
- }
- }
- }
-
- MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end);
-
- memset(&d->m_huff_count[0][0], 0,
- sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0);
- memset(&d->m_huff_count[1][0], 0,
- sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1);
-
- d->m_pLZ_code_buf = d->m_lz_code_buf + 1;
- d->m_pLZ_flags = d->m_lz_code_buf;
- d->m_num_flags_left = 8;
- d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes;
- d->m_total_lz_bytes = 0;
- d->m_block_index++;
-
- if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) {
- if (d->m_pPut_buf_func) {
- *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf;
- if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user))
- return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED);
- } else if (pOutput_buf_start == d->m_output_buf) {
- int bytes_to_copy = (int)MZ_MIN(
- (size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs));
- memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf,
- bytes_to_copy);
- d->m_out_buf_ofs += bytes_to_copy;
- if ((n -= bytes_to_copy) != 0) {
- d->m_output_flush_ofs = bytes_to_copy;
- d->m_output_flush_remaining = n;
- }
- } else {
- d->m_out_buf_ofs += n;
- }
- }
-
- return d->m_output_flush_remaining;
-}
-
-#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
-#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16 *)(p)
-static MZ_FORCEINLINE void tdefl_find_match(
- tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist,
- mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) {
- mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK,
- match_len = *pMatch_len, probe_pos = pos, next_probe_pos,
- probe_len;
- mz_uint num_probes_left = d->m_max_probes[match_len >= 32];
- const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q;
- mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]),
- s01 = TDEFL_READ_UNALIGNED_WORD(s);
- MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN);
- if (max_match_len <= match_len) return;
- for (;;) {
- for (;;) {
- if (--num_probes_left == 0) return;
-#define TDEFL_PROBE \
- next_probe_pos = d->m_next[probe_pos]; \
- if ((!next_probe_pos) || \
- ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \
- return; \
- probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \
- if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) \
- break;
- TDEFL_PROBE;
- TDEFL_PROBE;
- TDEFL_PROBE;
- }
- if (!dist) break;
- q = (const mz_uint16 *)(d->m_dict + probe_pos);
- if (TDEFL_READ_UNALIGNED_WORD(q) != s01) continue;
- p = s;
- probe_len = 32;
- do {
- } while (
- (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) &&
- (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) &&
- (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) &&
- (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) &&
- (--probe_len > 0));
- if (!probe_len) {
- *pMatch_dist = dist;
- *pMatch_len = MZ_MIN(max_match_len, TDEFL_MAX_MATCH_LEN);
- break;
- } else if ((probe_len = ((mz_uint)(p - s) * 2) +
- (mz_uint)(*(const mz_uint8 *)p ==
- *(const mz_uint8 *)q)) > match_len) {
- *pMatch_dist = dist;
- if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) ==
- max_match_len)
- break;
- c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]);
- }
- }
-}
-#else
-static MZ_FORCEINLINE void tdefl_find_match(
- tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist,
- mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) {
- mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK,
- match_len = *pMatch_len, probe_pos = pos, next_probe_pos,
- probe_len;
- mz_uint num_probes_left = d->m_max_probes[match_len >= 32];
- const mz_uint8 *s = d->m_dict + pos, *p, *q;
- mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1];
- MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN);
- if (max_match_len <= match_len) return;
- for (;;) {
- for (;;) {
- if (--num_probes_left == 0) return;
-#define TDEFL_PROBE \
- next_probe_pos = d->m_next[probe_pos]; \
- if ((!next_probe_pos) || \
- ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \
- return; \
- probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \
- if ((d->m_dict[probe_pos + match_len] == c0) && \
- (d->m_dict[probe_pos + match_len - 1] == c1)) \
- break;
- TDEFL_PROBE;
- TDEFL_PROBE;
- TDEFL_PROBE;
- }
- if (!dist) break;
- p = s;
- q = d->m_dict + probe_pos;
- for (probe_len = 0; probe_len < max_match_len; probe_len++)
- if (*p++ != *q++) break;
- if (probe_len > match_len) {
- *pMatch_dist = dist;
- if ((*pMatch_len = match_len = probe_len) == max_match_len) return;
- c0 = d->m_dict[pos + match_len];
- c1 = d->m_dict[pos + match_len - 1];
- }
- }
-}
-#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
-
-#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
-static mz_bool tdefl_compress_fast(tdefl_compressor *d) {
- // Faster, minimally featured LZRW1-style match+parse loop with better
- // register utilization. Intended for applications where raw throughput is
- // valued more highly than ratio.
- mz_uint lookahead_pos = d->m_lookahead_pos,
- lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size,
- total_lz_bytes = d->m_total_lz_bytes,
- num_flags_left = d->m_num_flags_left;
- mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags;
- mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK;
-
- while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) {
- const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096;
- mz_uint dst_pos =
- (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK;
- mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(
- d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size);
- d->m_src_buf_left -= num_bytes_to_process;
- lookahead_size += num_bytes_to_process;
-
- while (num_bytes_to_process) {
- mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process);
- memcpy(d->m_dict + dst_pos, d->m_pSrc, n);
- if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
- memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc,
- MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos));
- d->m_pSrc += n;
- dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK;
- num_bytes_to_process -= n;
- }
-
- dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size);
- if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE))
- break;
-
- while (lookahead_size >= 4) {
- mz_uint cur_match_dist, cur_match_len = 1;
- mz_uint8 *pCur_dict = d->m_dict + cur_pos;
- mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF;
- mz_uint hash =
- (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) &
- TDEFL_LEVEL1_HASH_SIZE_MASK;
- mz_uint probe_pos = d->m_hash[hash];
- d->m_hash[hash] = (mz_uint16)lookahead_pos;
-
- if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <=
- dict_size) &&
- ((*(const mz_uint32 *)(d->m_dict +
- (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) &
- 0xFFFFFF) == first_trigram)) {
- const mz_uint16 *p = (const mz_uint16 *)pCur_dict;
- const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos);
- mz_uint32 probe_len = 32;
- do {
- } while ((TDEFL_READ_UNALIGNED_WORD(++p) ==
- TDEFL_READ_UNALIGNED_WORD(++q)) &&
- (TDEFL_READ_UNALIGNED_WORD(++p) ==
- TDEFL_READ_UNALIGNED_WORD(++q)) &&
- (TDEFL_READ_UNALIGNED_WORD(++p) ==
- TDEFL_READ_UNALIGNED_WORD(++q)) &&
- (TDEFL_READ_UNALIGNED_WORD(++p) ==
- TDEFL_READ_UNALIGNED_WORD(++q)) &&
- (--probe_len > 0));
- cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) +
- (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q);
- if (!probe_len)
- cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0;
-
- if ((cur_match_len < TDEFL_MIN_MATCH_LEN) ||
- ((cur_match_len == TDEFL_MIN_MATCH_LEN) &&
- (cur_match_dist >= 8U * 1024U))) {
- cur_match_len = 1;
- *pLZ_code_buf++ = (mz_uint8)first_trigram;
- *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
- d->m_huff_count[0][(mz_uint8)first_trigram]++;
- } else {
- mz_uint32 s0, s1;
- cur_match_len = MZ_MIN(cur_match_len, lookahead_size);
-
- MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) &&
- (cur_match_dist >= 1) &&
- (cur_match_dist <= TDEFL_LZ_DICT_SIZE));
-
- cur_match_dist--;
-
- pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN);
- *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist;
- pLZ_code_buf += 3;
- *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80);
-
- s0 = s_tdefl_small_dist_sym[cur_match_dist & 511];
- s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8];
- d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++;
-
- d->m_huff_count[0][s_tdefl_len_sym[cur_match_len -
- TDEFL_MIN_MATCH_LEN]]++;
- }
- } else {
- *pLZ_code_buf++ = (mz_uint8)first_trigram;
- *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
- d->m_huff_count[0][(mz_uint8)first_trigram]++;
- }
-
- if (--num_flags_left == 0) {
- num_flags_left = 8;
- pLZ_flags = pLZ_code_buf++;
- }
-
- total_lz_bytes += cur_match_len;
- lookahead_pos += cur_match_len;
- dict_size = MZ_MIN(dict_size + cur_match_len, TDEFL_LZ_DICT_SIZE);
- cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK;
- MZ_ASSERT(lookahead_size >= cur_match_len);
- lookahead_size -= cur_match_len;
-
- if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) {
- int n;
- d->m_lookahead_pos = lookahead_pos;
- d->m_lookahead_size = lookahead_size;
- d->m_dict_size = dict_size;
- d->m_total_lz_bytes = total_lz_bytes;
- d->m_pLZ_code_buf = pLZ_code_buf;
- d->m_pLZ_flags = pLZ_flags;
- d->m_num_flags_left = num_flags_left;
- if ((n = tdefl_flush_block(d, 0)) != 0)
- return (n < 0) ? MZ_FALSE : MZ_TRUE;
- total_lz_bytes = d->m_total_lz_bytes;
- pLZ_code_buf = d->m_pLZ_code_buf;
- pLZ_flags = d->m_pLZ_flags;
- num_flags_left = d->m_num_flags_left;
- }
- }
-
- while (lookahead_size) {
- mz_uint8 lit = d->m_dict[cur_pos];
-
- total_lz_bytes++;
- *pLZ_code_buf++ = lit;
- *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
- if (--num_flags_left == 0) {
- num_flags_left = 8;
- pLZ_flags = pLZ_code_buf++;
- }
-
- d->m_huff_count[0][lit]++;
-
- lookahead_pos++;
- dict_size = MZ_MIN(dict_size + 1, TDEFL_LZ_DICT_SIZE);
- cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK;
- lookahead_size--;
-
- if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) {
- int n;
- d->m_lookahead_pos = lookahead_pos;
- d->m_lookahead_size = lookahead_size;
- d->m_dict_size = dict_size;
- d->m_total_lz_bytes = total_lz_bytes;
- d->m_pLZ_code_buf = pLZ_code_buf;
- d->m_pLZ_flags = pLZ_flags;
- d->m_num_flags_left = num_flags_left;
- if ((n = tdefl_flush_block(d, 0)) != 0)
- return (n < 0) ? MZ_FALSE : MZ_TRUE;
- total_lz_bytes = d->m_total_lz_bytes;
- pLZ_code_buf = d->m_pLZ_code_buf;
- pLZ_flags = d->m_pLZ_flags;
- num_flags_left = d->m_num_flags_left;
- }
- }
- }
-
- d->m_lookahead_pos = lookahead_pos;
- d->m_lookahead_size = lookahead_size;
- d->m_dict_size = dict_size;
- d->m_total_lz_bytes = total_lz_bytes;
- d->m_pLZ_code_buf = pLZ_code_buf;
- d->m_pLZ_flags = pLZ_flags;
- d->m_num_flags_left = num_flags_left;
- return MZ_TRUE;
-}
-#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
-
-static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d,
- mz_uint8 lit) {
- d->m_total_lz_bytes++;
- *d->m_pLZ_code_buf++ = lit;
- *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1);
- if (--d->m_num_flags_left == 0) {
- d->m_num_flags_left = 8;
- d->m_pLZ_flags = d->m_pLZ_code_buf++;
- }
- d->m_huff_count[0][lit]++;
-}
-
-static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d,
- mz_uint match_len,
- mz_uint match_dist) {
- mz_uint32 s0, s1;
-
- MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) &&
- (match_dist <= TDEFL_LZ_DICT_SIZE));
-
- d->m_total_lz_bytes += match_len;
-
- d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN);
-
- match_dist -= 1;
- d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF);
- d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8);
- d->m_pLZ_code_buf += 3;
-
- *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80);
- if (--d->m_num_flags_left == 0) {
- d->m_num_flags_left = 8;
- d->m_pLZ_flags = d->m_pLZ_code_buf++;
- }
-
- s0 = s_tdefl_small_dist_sym[match_dist & 511];
- s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127];
- d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++;
-
- if (match_len >= TDEFL_MIN_MATCH_LEN)
- d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++;
-}
-
-static mz_bool tdefl_compress_normal(tdefl_compressor *d) {
- const mz_uint8 *pSrc = d->m_pSrc;
- size_t src_buf_left = d->m_src_buf_left;
- tdefl_flush flush = d->m_flush;
-
- while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) {
- mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos;
- // Update dictionary and hash chains. Keeps the lookahead size equal to
- // TDEFL_MAX_MATCH_LEN.
- if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) {
- mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) &
- TDEFL_LZ_DICT_SIZE_MASK,
- ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2;
- mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK]
- << TDEFL_LZ_HASH_SHIFT) ^
- d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK];
- mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(
- src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size);
- const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process;
- src_buf_left -= num_bytes_to_process;
- d->m_lookahead_size += num_bytes_to_process;
- while (pSrc != pSrc_end) {
- mz_uint8 c = *pSrc++;
- d->m_dict[dst_pos] = c;
- if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
- d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c;
- hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1);
- d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash];
- d->m_hash[hash] = (mz_uint16)(ins_pos);
- dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK;
- ins_pos++;
- }
- } else {
- while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) {
- mz_uint8 c = *pSrc++;
- mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) &
- TDEFL_LZ_DICT_SIZE_MASK;
- src_buf_left--;
- d->m_dict[dst_pos] = c;
- if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
- d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c;
- if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) {
- mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2;
- mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK]
- << (TDEFL_LZ_HASH_SHIFT * 2)) ^
- (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]
- << TDEFL_LZ_HASH_SHIFT) ^
- c) &
- (TDEFL_LZ_HASH_SIZE - 1);
- d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash];
- d->m_hash[hash] = (mz_uint16)(ins_pos);
- }
- }
- }
- d->m_dict_size =
- MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size);
- if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) break;
-
- // Simple lazy/greedy parsing state machine.
- len_to_move = 1;
- cur_match_dist = 0;
- cur_match_len =
- d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1);
- cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK;
- if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) {
- if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) {
- mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK];
- cur_match_len = 0;
- while (cur_match_len < d->m_lookahead_size) {
- if (d->m_dict[cur_pos + cur_match_len] != c) break;
- cur_match_len++;
- }
- if (cur_match_len < TDEFL_MIN_MATCH_LEN)
- cur_match_len = 0;
- else
- cur_match_dist = 1;
- }
- } else {
- tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size,
- d->m_lookahead_size, &cur_match_dist, &cur_match_len);
- }
- if (((cur_match_len == TDEFL_MIN_MATCH_LEN) &&
- (cur_match_dist >= 8U * 1024U)) ||
- (cur_pos == cur_match_dist) ||
- ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) {
- cur_match_dist = cur_match_len = 0;
- }
- if (d->m_saved_match_len) {
- if (cur_match_len > d->m_saved_match_len) {
- tdefl_record_literal(d, (mz_uint8)d->m_saved_lit);
- if (cur_match_len >= 128) {
- tdefl_record_match(d, cur_match_len, cur_match_dist);
- d->m_saved_match_len = 0;
- len_to_move = cur_match_len;
- } else {
- d->m_saved_lit = d->m_dict[cur_pos];
- d->m_saved_match_dist = cur_match_dist;
- d->m_saved_match_len = cur_match_len;
- }
- } else {
- tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist);
- len_to_move = d->m_saved_match_len - 1;
- d->m_saved_match_len = 0;
- }
- } else if (!cur_match_dist)
- tdefl_record_literal(d,
- d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]);
- else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) ||
- (cur_match_len >= 128)) {
- tdefl_record_match(d, cur_match_len, cur_match_dist);
- len_to_move = cur_match_len;
- } else {
- d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)];
- d->m_saved_match_dist = cur_match_dist;
- d->m_saved_match_len = cur_match_len;
- }
- // Move the lookahead forward by len_to_move bytes.
- d->m_lookahead_pos += len_to_move;
- MZ_ASSERT(d->m_lookahead_size >= len_to_move);
- d->m_lookahead_size -= len_to_move;
- d->m_dict_size =
- MZ_MIN(d->m_dict_size + len_to_move, (mz_uint)TDEFL_LZ_DICT_SIZE);
- // Check if it's time to flush the current LZ codes to the internal output
- // buffer.
- if ((d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) ||
- ((d->m_total_lz_bytes > 31 * 1024) &&
- (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >=
- d->m_total_lz_bytes) ||
- (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))) {
- int n;
- d->m_pSrc = pSrc;
- d->m_src_buf_left = src_buf_left;
- if ((n = tdefl_flush_block(d, 0)) != 0)
- return (n < 0) ? MZ_FALSE : MZ_TRUE;
- }
- }
-
- d->m_pSrc = pSrc;
- d->m_src_buf_left = src_buf_left;
- return MZ_TRUE;
-}
-
-static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) {
- if (d->m_pIn_buf_size) {
- *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf;
- }
-
- if (d->m_pOut_buf_size) {
- size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs,
- d->m_output_flush_remaining);
- memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs,
- d->m_output_buf + d->m_output_flush_ofs, n);
- d->m_output_flush_ofs += (mz_uint)n;
- d->m_output_flush_remaining -= (mz_uint)n;
- d->m_out_buf_ofs += n;
-
- *d->m_pOut_buf_size = d->m_out_buf_ofs;
- }
-
- return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE
- : TDEFL_STATUS_OKAY;
-}
-
-tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf,
- size_t *pIn_buf_size, void *pOut_buf,
- size_t *pOut_buf_size, tdefl_flush flush) {
- if (!d) {
- if (pIn_buf_size) *pIn_buf_size = 0;
- if (pOut_buf_size) *pOut_buf_size = 0;
- return TDEFL_STATUS_BAD_PARAM;
- }
-
- d->m_pIn_buf = pIn_buf;
- d->m_pIn_buf_size = pIn_buf_size;
- d->m_pOut_buf = pOut_buf;
- d->m_pOut_buf_size = pOut_buf_size;
- d->m_pSrc = (const mz_uint8 *)(pIn_buf);
- d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0;
- d->m_out_buf_ofs = 0;
- d->m_flush = flush;
-
- if (((d->m_pPut_buf_func != NULL) ==
- ((pOut_buf != NULL) || (pOut_buf_size != NULL))) ||
- (d->m_prev_return_status != TDEFL_STATUS_OKAY) ||
- (d->m_wants_to_finish && (flush != TDEFL_FINISH)) ||
- (pIn_buf_size && *pIn_buf_size && !pIn_buf) ||
- (pOut_buf_size && *pOut_buf_size && !pOut_buf)) {
- if (pIn_buf_size) *pIn_buf_size = 0;
- if (pOut_buf_size) *pOut_buf_size = 0;
- return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM);
- }
- d->m_wants_to_finish |= (flush == TDEFL_FINISH);
-
- if ((d->m_output_flush_remaining) || (d->m_finished))
- return (d->m_prev_return_status = tdefl_flush_output_buffer(d));
-
-#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
- if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) &&
- ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) &&
- ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS |
- TDEFL_RLE_MATCHES)) == 0)) {
- if (!tdefl_compress_fast(d)) return d->m_prev_return_status;
- } else
-#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
- {
- if (!tdefl_compress_normal(d)) return d->m_prev_return_status;
- }
-
- if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) &&
- (pIn_buf))
- d->m_adler32 =
- (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf,
- d->m_pSrc - (const mz_uint8 *)pIn_buf);
-
- if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) &&
- (!d->m_output_flush_remaining)) {
- if (tdefl_flush_block(d, flush) < 0) return d->m_prev_return_status;
- d->m_finished = (flush == TDEFL_FINISH);
- if (flush == TDEFL_FULL_FLUSH) {
- MZ_CLEAR_OBJ(d->m_hash);
- MZ_CLEAR_OBJ(d->m_next);
- d->m_dict_size = 0;
- }
- }
-
- return (d->m_prev_return_status = tdefl_flush_output_buffer(d));
-}
-
-tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf,
- size_t in_buf_size, tdefl_flush flush) {
- MZ_ASSERT(d->m_pPut_buf_func);
- return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush);
-}
-
-tdefl_status tdefl_init(tdefl_compressor *d,
- tdefl_put_buf_func_ptr pPut_buf_func,
- void *pPut_buf_user, int flags) {
- d->m_pPut_buf_func = pPut_buf_func;
- d->m_pPut_buf_user = pPut_buf_user;
- d->m_flags = (mz_uint)(flags);
- d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3;
- d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0;
- d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3;
- if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_OBJ(d->m_hash);
- d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size =
- d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0;
- d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished =
- d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0;
- d->m_pLZ_code_buf = d->m_lz_code_buf + 1;
- d->m_pLZ_flags = d->m_lz_code_buf;
- d->m_num_flags_left = 8;
- d->m_pOutput_buf = d->m_output_buf;
- d->m_pOutput_buf_end = d->m_output_buf;
- d->m_prev_return_status = TDEFL_STATUS_OKAY;
- d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0;
- d->m_adler32 = 1;
- d->m_pIn_buf = NULL;
- d->m_pOut_buf = NULL;
- d->m_pIn_buf_size = NULL;
- d->m_pOut_buf_size = NULL;
- d->m_flush = TDEFL_NO_FLUSH;
- d->m_pSrc = NULL;
- d->m_src_buf_left = 0;
- d->m_out_buf_ofs = 0;
- memset(&d->m_huff_count[0][0], 0,
- sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0);
- memset(&d->m_huff_count[1][0], 0,
- sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1);
- return TDEFL_STATUS_OKAY;
-}
-
-tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) {
- return d->m_prev_return_status;
-}
-
-mz_uint32 tdefl_get_adler32(tdefl_compressor *d) { return d->m_adler32; }
-
-mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len,
- tdefl_put_buf_func_ptr pPut_buf_func,
- void *pPut_buf_user, int flags) {
- tdefl_compressor *pComp;
- mz_bool succeeded;
- if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) return MZ_FALSE;
- pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor));
- if (!pComp) return MZ_FALSE;
- succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) ==
- TDEFL_STATUS_OKAY);
- succeeded =
- succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) ==
- TDEFL_STATUS_DONE);
- MZ_FREE(pComp);
- return succeeded;
-}
-
-typedef struct {
- size_t m_size, m_capacity;
- mz_uint8 *m_pBuf;
- mz_bool m_expandable;
-} tdefl_output_buffer;
-
-static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len,
- void *pUser) {
- tdefl_output_buffer *p = (tdefl_output_buffer *)pUser;
- size_t new_size = p->m_size + len;
- if (new_size > p->m_capacity) {
- size_t new_capacity = p->m_capacity;
- mz_uint8 *pNew_buf;
- if (!p->m_expandable) return MZ_FALSE;
- do {
- new_capacity = MZ_MAX(128U, new_capacity << 1U);
- } while (new_size > new_capacity);
- pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity);
- if (!pNew_buf) return MZ_FALSE;
- p->m_pBuf = pNew_buf;
- p->m_capacity = new_capacity;
- }
- memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len);
- p->m_size = new_size;
- return MZ_TRUE;
-}
-
-void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len,
- size_t *pOut_len, int flags) {
- tdefl_output_buffer out_buf;
- MZ_CLEAR_OBJ(out_buf);
- if (!pOut_len)
- return MZ_FALSE;
- else
- *pOut_len = 0;
- out_buf.m_expandable = MZ_TRUE;
- if (!tdefl_compress_mem_to_output(
- pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags))
- return NULL;
- *pOut_len = out_buf.m_size;
- return out_buf.m_pBuf;
-}
-
-size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len,
- const void *pSrc_buf, size_t src_buf_len,
- int flags) {
- tdefl_output_buffer out_buf;
- MZ_CLEAR_OBJ(out_buf);
- if (!pOut_buf) return 0;
- out_buf.m_pBuf = (mz_uint8 *)pOut_buf;
- out_buf.m_capacity = out_buf_len;
- if (!tdefl_compress_mem_to_output(
- pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags))
- return 0;
- return out_buf.m_size;
-}
-
-#ifndef MINIZ_NO_ZLIB_APIS
-static const mz_uint s_tdefl_num_probes[11] = {0, 1, 6, 32, 16, 32,
- 128, 256, 512, 768, 1500};
-
-// level may actually range from [0,10] (10 is a "hidden" max level, where we
-// want a bit more compression and it's fine if throughput to fall off a cliff
-// on some files).
-mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits,
- int strategy) {
- mz_uint comp_flags =
- s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] |
- ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0);
- if (window_bits > 0) comp_flags |= TDEFL_WRITE_ZLIB_HEADER;
-
- if (!level)
- comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS;
- else if (strategy == MZ_FILTERED)
- comp_flags |= TDEFL_FILTER_MATCHES;
- else if (strategy == MZ_HUFFMAN_ONLY)
- comp_flags &= ~TDEFL_MAX_PROBES_MASK;
- else if (strategy == MZ_FIXED)
- comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS;
- else if (strategy == MZ_RLE)
- comp_flags |= TDEFL_RLE_MATCHES;
-
- return comp_flags;
-}
-#endif // MINIZ_NO_ZLIB_APIS
-
-#ifdef _MSC_VER
-#pragma warning(push)
-#pragma warning(disable : 4204) // nonstandard extension used : non-constant
- // aggregate initializer (also supported by GNU
- // C and C99, so no big deal)
-#pragma warning(disable : 4244) // 'initializing': conversion from '__int64' to
- // 'int', possible loss of data
-#pragma warning(disable : 4267) // 'argument': conversion from '__int64' to
- // 'int', possible loss of data
-#pragma warning(disable : 4996) // 'strdup': The POSIX name for this item is
- // deprecated. Instead, use the ISO C and C++
- // conformant name: _strdup.
-#endif
-
-// Simple PNG writer function by Alex Evans, 2011. Released into the public
-// domain: https://gist.github.com/908299, more context at
-// http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/.
-// This is actually a modification of Alex's original code so PNG files
-// generated by this function pass pngcheck.
-void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w,
- int h, int num_chans,
- size_t *pLen_out,
- mz_uint level, mz_bool flip) {
- // Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was
- // defined.
- static const mz_uint s_tdefl_png_num_probes[11] = {
- 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500};
- tdefl_compressor *pComp =
- (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor));
- tdefl_output_buffer out_buf;
- int i, bpl = w * num_chans, y, z;
- mz_uint32 c;
- *pLen_out = 0;
- if (!pComp) return NULL;
- MZ_CLEAR_OBJ(out_buf);
- out_buf.m_expandable = MZ_TRUE;
- out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h);
- if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) {
- MZ_FREE(pComp);
- return NULL;
- }
- // write dummy header
- for (z = 41; z; --z) tdefl_output_buffer_putter(&z, 1, &out_buf);
- // compress image data
- tdefl_init(
- pComp, tdefl_output_buffer_putter, &out_buf,
- s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER);
- for (y = 0; y < h; ++y) {
- tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH);
- tdefl_compress_buffer(pComp,
- (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl,
- bpl, TDEFL_NO_FLUSH);
- }
- if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) !=
- TDEFL_STATUS_DONE) {
- MZ_FREE(pComp);
- MZ_FREE(out_buf.m_pBuf);
- return NULL;
- }
- // write real header
- *pLen_out = out_buf.m_size - 41;
- {
- static const mz_uint8 chans[] = {0x00, 0x00, 0x04, 0x02, 0x06};
- mz_uint8 pnghdr[41] = {0x89,
- 0x50,
- 0x4e,
- 0x47,
- 0x0d,
- 0x0a,
- 0x1a,
- 0x0a,
- 0x00,
- 0x00,
- 0x00,
- 0x0d,
- 0x49,
- 0x48,
- 0x44,
- 0x52,
- 0,
- 0,
- (mz_uint8)(w >> 8),
- (mz_uint8)w,
- 0,
- 0,
- (mz_uint8)(h >> 8),
- (mz_uint8)h,
- 8,
- chans[num_chans],
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- (mz_uint8)(*pLen_out >> 24),
- (mz_uint8)(*pLen_out >> 16),
- (mz_uint8)(*pLen_out >> 8),
- (mz_uint8)*pLen_out,
- 0x49,
- 0x44,
- 0x41,
- 0x54};
- c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17);
- for (i = 0; i < 4; ++i, c <<= 8)
- ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24);
- memcpy(out_buf.m_pBuf, pnghdr, 41);
- }
- // write footer (IDAT CRC-32, followed by IEND chunk)
- if (!tdefl_output_buffer_putter(
- "\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) {
- *pLen_out = 0;
- MZ_FREE(pComp);
- MZ_FREE(out_buf.m_pBuf);
- return NULL;
- }
- c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4,
- *pLen_out + 4);
- for (i = 0; i < 4; ++i, c <<= 8)
- (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24);
- // compute final size of file, grab compressed data buffer and return
- *pLen_out += 57;
- MZ_FREE(pComp);
- return out_buf.m_pBuf;
-}
-void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h,
- int num_chans, size_t *pLen_out) {
- // Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we
- // can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's
- // where #defined out)
- return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans,
- pLen_out, 6, MZ_FALSE);
-}
-
-// ------------------- .ZIP archive reading
-
-#ifndef MINIZ_NO_ARCHIVE_APIS
-#error "No arvhive APIs"
-
-#ifdef MINIZ_NO_STDIO
-#define MZ_FILE void *
-#else
-#include <stdio.h>
-#include <sys/stat.h>
-
-#if defined(_MSC_VER) || defined(__MINGW64__)
-static FILE *mz_fopen(const char *pFilename, const char *pMode) {
- FILE *pFile = NULL;
- fopen_s(&pFile, pFilename, pMode);
- return pFile;
-}
-static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) {
- FILE *pFile = NULL;
- if (freopen_s(&pFile, pPath, pMode, pStream)) return NULL;
- return pFile;
-}
-#ifndef MINIZ_NO_TIME
-#include <sys/utime.h>
-#endif
-#define MZ_FILE FILE
-#define MZ_FOPEN mz_fopen
-#define MZ_FCLOSE fclose
-#define MZ_FREAD fread
-#define MZ_FWRITE fwrite
-#define MZ_FTELL64 _ftelli64
-#define MZ_FSEEK64 _fseeki64
-#define MZ_FILE_STAT_STRUCT _stat
-#define MZ_FILE_STAT _stat
-#define MZ_FFLUSH fflush
-#define MZ_FREOPEN mz_freopen
-#define MZ_DELETE_FILE remove
-#elif defined(__MINGW32__)
-#ifndef MINIZ_NO_TIME
-#include <sys/utime.h>
-#endif
-#define MZ_FILE FILE
-#define MZ_FOPEN(f, m) fopen(f, m)
-#define MZ_FCLOSE fclose
-#define MZ_FREAD fread
-#define MZ_FWRITE fwrite
-#define MZ_FTELL64 ftello64
-#define MZ_FSEEK64 fseeko64
-#define MZ_FILE_STAT_STRUCT _stat
-#define MZ_FILE_STAT _stat
-#define MZ_FFLUSH fflush
-#define MZ_FREOPEN(f, m, s) freopen(f, m, s)
-#define MZ_DELETE_FILE remove
-#elif defined(__TINYC__)
-#ifndef MINIZ_NO_TIME
-#include <sys/utime.h>
-#endif
-#define MZ_FILE FILE
-#define MZ_FOPEN(f, m) fopen(f, m)
-#define MZ_FCLOSE fclose
-#define MZ_FREAD fread
-#define MZ_FWRITE fwrite
-#define MZ_FTELL64 ftell
-#define MZ_FSEEK64 fseek
-#define MZ_FILE_STAT_STRUCT stat
-#define MZ_FILE_STAT stat
-#define MZ_FFLUSH fflush
-#define MZ_FREOPEN(f, m, s) freopen(f, m, s)
-#define MZ_DELETE_FILE remove
-#elif defined(__GNUC__) && defined(_LARGEFILE64_SOURCE) && _LARGEFILE64_SOURCE
-#ifndef MINIZ_NO_TIME
-#include <utime.h>
-#endif
-#define MZ_FILE FILE
-#define MZ_FOPEN(f, m) fopen64(f, m)
-#define MZ_FCLOSE fclose
-#define MZ_FREAD fread
-#define MZ_FWRITE fwrite
-#define MZ_FTELL64 ftello64
-#define MZ_FSEEK64 fseeko64
-#define MZ_FILE_STAT_STRUCT stat64
-#define MZ_FILE_STAT stat64
-#define MZ_FFLUSH fflush
-#define MZ_FREOPEN(p, m, s) freopen64(p, m, s)
-#define MZ_DELETE_FILE remove
-#else
-#ifndef MINIZ_NO_TIME
-#include <utime.h>
-#endif
-#define MZ_FILE FILE
-#define MZ_FOPEN(f, m) fopen(f, m)
-#define MZ_FCLOSE fclose
-#define MZ_FREAD fread
-#define MZ_FWRITE fwrite
-#define MZ_FTELL64 ftello
-#define MZ_FSEEK64 fseeko
-#define MZ_FILE_STAT_STRUCT stat
-#define MZ_FILE_STAT stat
-#define MZ_FFLUSH fflush
-#define MZ_FREOPEN(f, m, s) freopen(f, m, s)
-#define MZ_DELETE_FILE remove
-#endif // #ifdef _MSC_VER
-#endif // #ifdef MINIZ_NO_STDIO
-
-#define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c))
-
-// Various ZIP archive enums. To completely avoid cross platform compiler
-// alignment and platform endian issues, miniz.c doesn't use structs for any of
-// this stuff.
-enum {
- // ZIP archive identifiers and record sizes
- MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50,
- MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50,
- MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50,
- MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30,
- MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46,
- MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22,
- // Central directory header record offsets
- MZ_ZIP_CDH_SIG_OFS = 0,
- MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4,
- MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6,
- MZ_ZIP_CDH_BIT_FLAG_OFS = 8,
- MZ_ZIP_CDH_METHOD_OFS = 10,
- MZ_ZIP_CDH_FILE_TIME_OFS = 12,
- MZ_ZIP_CDH_FILE_DATE_OFS = 14,
- MZ_ZIP_CDH_CRC32_OFS = 16,
- MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20,
- MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24,
- MZ_ZIP_CDH_FILENAME_LEN_OFS = 28,
- MZ_ZIP_CDH_EXTRA_LEN_OFS = 30,
- MZ_ZIP_CDH_COMMENT_LEN_OFS = 32,
- MZ_ZIP_CDH_DISK_START_OFS = 34,
- MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36,
- MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38,
- MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42,
- // Local directory header offsets
- MZ_ZIP_LDH_SIG_OFS = 0,
- MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4,
- MZ_ZIP_LDH_BIT_FLAG_OFS = 6,
- MZ_ZIP_LDH_METHOD_OFS = 8,
- MZ_ZIP_LDH_FILE_TIME_OFS = 10,
- MZ_ZIP_LDH_FILE_DATE_OFS = 12,
- MZ_ZIP_LDH_CRC32_OFS = 14,
- MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18,
- MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22,
- MZ_ZIP_LDH_FILENAME_LEN_OFS = 26,
- MZ_ZIP_LDH_EXTRA_LEN_OFS = 28,
- // End of central directory offsets
- MZ_ZIP_ECDH_SIG_OFS = 0,
- MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4,
- MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6,
- MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8,
- MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10,
- MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12,
- MZ_ZIP_ECDH_CDIR_OFS_OFS = 16,
- MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20,
-};
-
-typedef struct {
- void *m_p;
- size_t m_size, m_capacity;
- mz_uint m_element_size;
-} mz_zip_array;
-
-struct mz_zip_internal_state_tag {
- mz_zip_array m_central_dir;
- mz_zip_array m_central_dir_offsets;
- mz_zip_array m_sorted_central_dir_offsets;
- MZ_FILE *m_pFile;
- void *m_pMem;
- size_t m_mem_size;
- size_t m_mem_capacity;
-};
-
-#define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) \
- (array_ptr)->m_element_size = element_size
-#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) \
- ((element_type *)((array_ptr)->m_p))[index]
-
-static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip,
- mz_zip_array *pArray) {
- pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p);
- memset(pArray, 0, sizeof(mz_zip_array));
-}
-
-static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip,
- mz_zip_array *pArray,
- size_t min_new_capacity,
- mz_uint growing) {
- void *pNew_p;
- size_t new_capacity = min_new_capacity;
- MZ_ASSERT(pArray->m_element_size);
- if (pArray->m_capacity >= min_new_capacity) return MZ_TRUE;
- if (growing) {
- new_capacity = MZ_MAX(1, pArray->m_capacity);
- while (new_capacity < min_new_capacity) new_capacity *= 2;
- }
- if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p,
- pArray->m_element_size, new_capacity)))
- return MZ_FALSE;
- pArray->m_p = pNew_p;
- pArray->m_capacity = new_capacity;
- return MZ_TRUE;
-}
-
-static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip,
- mz_zip_array *pArray,
- size_t new_capacity,
- mz_uint growing) {
- if (new_capacity > pArray->m_capacity) {
- if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing))
- return MZ_FALSE;
- }
- return MZ_TRUE;
-}
-
-static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip,
- mz_zip_array *pArray,
- size_t new_size,
- mz_uint growing) {
- if (new_size > pArray->m_capacity) {
- if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing))
- return MZ_FALSE;
- }
- pArray->m_size = new_size;
- return MZ_TRUE;
-}
-
-static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip,
- mz_zip_array *pArray,
- size_t n) {
- return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE);
-}
-
-static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip,
- mz_zip_array *pArray,
- const void *pElements,
- size_t n) {
- size_t orig_size = pArray->m_size;
- if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE))
- return MZ_FALSE;
- memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size,
- pElements, n * pArray->m_element_size);
- return MZ_TRUE;
-}
-
-#ifndef MINIZ_NO_TIME
-static time_t mz_zip_dos_to_time_t(int dos_time, int dos_date) {
- struct tm tm;
- memset(&tm, 0, sizeof(tm));
- tm.tm_isdst = -1;
- tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900;
- tm.tm_mon = ((dos_date >> 5) & 15) - 1;
- tm.tm_mday = dos_date & 31;
- tm.tm_hour = (dos_time >> 11) & 31;
- tm.tm_min = (dos_time >> 5) & 63;
- tm.tm_sec = (dos_time << 1) & 62;
- return mktime(&tm);
-}
-
-static void mz_zip_time_to_dos_time(time_t time, mz_uint16 *pDOS_time,
- mz_uint16 *pDOS_date) {
-#ifdef _MSC_VER
- struct tm tm_struct;
- struct tm *tm = &tm_struct;
- errno_t err = localtime_s(tm, &time);
- if (err) {
- *pDOS_date = 0;
- *pDOS_time = 0;
- return;
- }
-#else
- struct tm *tm = localtime(&time);
-#endif
- *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) +
- ((tm->tm_sec) >> 1));
- *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) +
- ((tm->tm_mon + 1) << 5) + tm->tm_mday);
-}
-#endif
-
-#ifndef MINIZ_NO_STDIO
-static mz_bool mz_zip_get_file_modified_time(const char *pFilename,
- mz_uint16 *pDOS_time,
- mz_uint16 *pDOS_date) {
-#ifdef MINIZ_NO_TIME
- (void)pFilename;
- *pDOS_date = *pDOS_time = 0;
-#else
- struct MZ_FILE_STAT_STRUCT file_stat;
- // On Linux with x86 glibc, this call will fail on large files (>= 0x80000000
- // bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh.
- if (MZ_FILE_STAT(pFilename, &file_stat) != 0) return MZ_FALSE;
- mz_zip_time_to_dos_time(file_stat.st_mtime, pDOS_time, pDOS_date);
-#endif // #ifdef MINIZ_NO_TIME
- return MZ_TRUE;
-}
-
-#ifndef MINIZ_NO_TIME
-static mz_bool mz_zip_set_file_times(const char *pFilename, time_t access_time,
- time_t modified_time) {
- struct utimbuf t;
- t.actime = access_time;
- t.modtime = modified_time;
- return !utime(pFilename, &t);
-}
-#endif // #ifndef MINIZ_NO_TIME
-#endif // #ifndef MINIZ_NO_STDIO
-
-static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip,
- mz_uint32 flags) {
- (void)flags;
- if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID))
- return MZ_FALSE;
-
- if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func;
- if (!pZip->m_pFree) pZip->m_pFree = def_free_func;
- if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func;
-
- pZip->m_zip_mode = MZ_ZIP_MODE_READING;
- pZip->m_archive_size = 0;
- pZip->m_central_directory_file_ofs = 0;
- pZip->m_total_files = 0;
-
- if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(
- pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state))))
- return MZ_FALSE;
- memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state));
- MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir,
- sizeof(mz_uint8));
- MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets,
- sizeof(mz_uint32));
- MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets,
- sizeof(mz_uint32));
- return MZ_TRUE;
-}
-
-static MZ_FORCEINLINE mz_bool
-mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array,
- const mz_zip_array *pCentral_dir_offsets,
- mz_uint l_index, mz_uint r_index) {
- const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(
- pCentral_dir_array, mz_uint8,
- MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32,
- l_index)),
- *pE;
- const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(
- pCentral_dir_array, mz_uint8,
- MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index));
- mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS),
- r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS);
- mz_uint8 l = 0, r = 0;
- pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
- pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
- pE = pL + MZ_MIN(l_len, r_len);
- while (pL < pE) {
- if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) break;
- pL++;
- pR++;
- }
- return (pL == pE) ? (l_len < r_len) : (l < r);
-}
-
-#define MZ_SWAP_UINT32(a, b) \
- do { \
- mz_uint32 t = a; \
- a = b; \
- b = t; \
- } \
- MZ_MACRO_END
-
-// Heap sort of lowercased filenames, used to help accelerate plain central
-// directory searches by mz_zip_reader_locate_file(). (Could also use qsort(),
-// but it could allocate memory.)
-static void mz_zip_reader_sort_central_dir_offsets_by_filename(
- mz_zip_archive *pZip) {
- mz_zip_internal_state *pState = pZip->m_pState;
- const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets;
- const mz_zip_array *pCentral_dir = &pState->m_central_dir;
- mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(
- &pState->m_sorted_central_dir_offsets, mz_uint32, 0);
- const int size = pZip->m_total_files;
- int start = (size - 2) >> 1, end;
- while (start >= 0) {
- int child, root = start;
- for (;;) {
- if ((child = (root << 1) + 1) >= size) break;
- child +=
- (((child + 1) < size) &&
- (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets,
- pIndices[child], pIndices[child + 1])));
- if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets,
- pIndices[root], pIndices[child]))
- break;
- MZ_SWAP_UINT32(pIndices[root], pIndices[child]);
- root = child;
- }
- start--;
- }
-
- end = size - 1;
- while (end > 0) {
- int child, root = 0;
- MZ_SWAP_UINT32(pIndices[end], pIndices[0]);
- for (;;) {
- if ((child = (root << 1) + 1) >= end) break;
- child +=
- (((child + 1) < end) &&
- mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets,
- pIndices[child], pIndices[child + 1]));
- if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets,
- pIndices[root], pIndices[child]))
- break;
- MZ_SWAP_UINT32(pIndices[root], pIndices[child]);
- root = child;
- }
- end--;
- }
-}
-
-static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip,
- mz_uint32 flags) {
- mz_uint cdir_size, num_this_disk, cdir_disk_index;
- mz_uint64 cdir_ofs;
- mz_int64 cur_file_ofs;
- const mz_uint8 *p;
- mz_uint32 buf_u32[4096 / sizeof(mz_uint32)];
- mz_uint8 *pBuf = (mz_uint8 *)buf_u32;
- mz_bool sort_central_dir =
- ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0);
- // Basic sanity checks - reject files which are too small, and check the first
- // 4 bytes of the file to make sure a local header is there.
- if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
- return MZ_FALSE;
- // Find the end of central directory record by scanning the file from the end
- // towards the beginning.
- cur_file_ofs =
- MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0);
- for (;;) {
- int i,
- n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs);
- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n)
- return MZ_FALSE;
- for (i = n - 4; i >= 0; --i)
- if (MZ_READ_LE32(pBuf + i) == MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) break;
- if (i >= 0) {
- cur_file_ofs += i;
- break;
- }
- if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >=
- (0xFFFF + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)))
- return MZ_FALSE;
- cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0);
- }
- // Read and verify the end of central directory record.
- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf,
- MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) !=
- MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
- return MZ_FALSE;
- if ((MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) !=
- MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) ||
- ((pZip->m_total_files =
- MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS)) !=
- MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS)))
- return MZ_FALSE;
-
- num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS);
- cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS);
- if (((num_this_disk | cdir_disk_index) != 0) &&
- ((num_this_disk != 1) || (cdir_disk_index != 1)))
- return MZ_FALSE;
-
- if ((cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS)) <
- pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)
- return MZ_FALSE;
-
- cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS);
- if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) return MZ_FALSE;
-
- pZip->m_central_directory_file_ofs = cdir_ofs;
-
- if (pZip->m_total_files) {
- mz_uint i, n;
-
- // Read the entire central directory into a heap block, and allocate another
- // heap block to hold the unsorted central dir file record offsets, and
- // another to hold the sorted indices.
- if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size,
- MZ_FALSE)) ||
- (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets,
- pZip->m_total_files, MZ_FALSE)))
- return MZ_FALSE;
-
- if (sort_central_dir) {
- if (!mz_zip_array_resize(pZip,
- &pZip->m_pState->m_sorted_central_dir_offsets,
- pZip->m_total_files, MZ_FALSE))
- return MZ_FALSE;
- }
-
- if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs,
- pZip->m_pState->m_central_dir.m_p,
- cdir_size) != cdir_size)
- return MZ_FALSE;
-
- // Now create an index into the central directory file records, do some
- // basic sanity checking on each record, and check for zip64 entries (which
- // are not yet supported).
- p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p;
- for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) {
- mz_uint total_header_size, comp_size, decomp_size, disk_index;
- if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) ||
- (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG))
- return MZ_FALSE;
- MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32,
- i) =
- (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p);
- if (sort_central_dir)
- MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets,
- mz_uint32, i) = i;
- comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
- decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
- if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) &&
- (decomp_size != comp_size)) ||
- (decomp_size && !comp_size) || (decomp_size == 0xFFFFFFFF) ||
- (comp_size == 0xFFFFFFFF))
- return MZ_FALSE;
- disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS);
- if ((disk_index != num_this_disk) && (disk_index != 1)) return MZ_FALSE;
- if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) +
- MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size)
- return MZ_FALSE;
- if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
- MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
- MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) +
- MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) >
- n)
- return MZ_FALSE;
- n -= total_header_size;
- p += total_header_size;
- }
- }
-
- if (sort_central_dir)
- mz_zip_reader_sort_central_dir_offsets_by_filename(pZip);
-
- return MZ_TRUE;
-}
-
-mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size,
- mz_uint32 flags) {
- if ((!pZip) || (!pZip->m_pRead)) return MZ_FALSE;
- if (!mz_zip_reader_init_internal(pZip, flags)) return MZ_FALSE;
- pZip->m_archive_size = size;
- if (!mz_zip_reader_read_central_dir(pZip, flags)) {
- mz_zip_reader_end(pZip);
- return MZ_FALSE;
- }
- return MZ_TRUE;
-}
-
-static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs,
- void *pBuf, size_t n) {
- mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
- size_t s = (file_ofs >= pZip->m_archive_size)
- ? 0
- : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n);
- memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s);
- return s;
-}
-
-mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem,
- size_t size, mz_uint32 flags) {
- if (!mz_zip_reader_init_internal(pZip, flags)) return MZ_FALSE;
- pZip->m_archive_size = size;
- pZip->m_pRead = mz_zip_mem_read_func;
- pZip->m_pIO_opaque = pZip;
-#ifdef __cplusplus
- pZip->m_pState->m_pMem = const_cast<void *>(pMem);
-#else
- pZip->m_pState->m_pMem = (void *)pMem;
-#endif
- pZip->m_pState->m_mem_size = size;
- if (!mz_zip_reader_read_central_dir(pZip, flags)) {
- mz_zip_reader_end(pZip);
- return MZ_FALSE;
- }
- return MZ_TRUE;
-}
-
-#ifndef MINIZ_NO_STDIO
-static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs,
- void *pBuf, size_t n) {
- mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
- mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);
- if (((mz_int64)file_ofs < 0) ||
- (((cur_ofs != (mz_int64)file_ofs)) &&
- (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET))))
- return 0;
- return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile);
-}
-
-mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename,
- mz_uint32 flags) {
- mz_uint64 file_size;
- MZ_FILE *pFile = MZ_FOPEN(pFilename, "rb");
- if (!pFile) return MZ_FALSE;
- if (MZ_FSEEK64(pFile, 0, SEEK_END)) {
- MZ_FCLOSE(pFile);
- return MZ_FALSE;
- }
- file_size = MZ_FTELL64(pFile);
- if (!mz_zip_reader_init_internal(pZip, flags)) {
- MZ_FCLOSE(pFile);
- return MZ_FALSE;
- }
- pZip->m_pRead = mz_zip_file_read_func;
- pZip->m_pIO_opaque = pZip;
- pZip->m_pState->m_pFile = pFile;
- pZip->m_archive_size = file_size;
- if (!mz_zip_reader_read_central_dir(pZip, flags)) {
- mz_zip_reader_end(pZip);
- return MZ_FALSE;
- }
- return MZ_TRUE;
-}
-#endif // #ifndef MINIZ_NO_STDIO
-
-mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) {
- return pZip ? pZip->m_total_files : 0;
-}
-
-static MZ_FORCEINLINE const mz_uint8 *mz_zip_reader_get_cdh(
- mz_zip_archive *pZip, mz_uint file_index) {
- if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files) ||
- (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
- return NULL;
- return &MZ_ZIP_ARRAY_ELEMENT(
- &pZip->m_pState->m_central_dir, mz_uint8,
- MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32,
- file_index));
-}
-
-mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip,
- mz_uint file_index) {
- mz_uint m_bit_flag;
- const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
- if (!p) return MZ_FALSE;
- m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
- return (m_bit_flag & 1);
-}
-
-mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip,
- mz_uint file_index) {
- mz_uint filename_len, external_attr;
- const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
- if (!p) return MZ_FALSE;
-
- // First see if the filename ends with a '/' character.
- filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
- if (filename_len) {
- if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/')
- return MZ_TRUE;
- }
-
- // Bugfix: This code was also checking if the internal attribute was non-zero,
- // which wasn't correct.
- // Most/all zip writers (hopefully) set DOS file/directory attributes in the
- // low 16-bits, so check for the DOS directory flag and ignore the source OS
- // ID in the created by field.
- // FIXME: Remove this check? Is it necessary - we already check the filename.
- external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS);
- if ((external_attr & 0x10) != 0) return MZ_TRUE;
-
- return MZ_FALSE;
-}
-
-mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index,
- mz_zip_archive_file_stat *pStat) {
- mz_uint n;
- const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
- if ((!p) || (!pStat)) return MZ_FALSE;
-
- // Unpack the central directory record.
- pStat->m_file_index = file_index;
- pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(
- &pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index);
- pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS);
- pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS);
- pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
- pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS);
-#ifndef MINIZ_NO_TIME
- pStat->m_time =
- mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS),
- MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS));
-#endif
- pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS);
- pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
- pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
- pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS);
- pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS);
- pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
-
- // Copy as much of the filename and comment as possible.
- n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
- n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1);
- memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n);
- pStat->m_filename[n] = '\0';
-
- n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS);
- n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1);
- pStat->m_comment_size = n;
- memcpy(pStat->m_comment,
- p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
- MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
- MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS),
- n);
- pStat->m_comment[n] = '\0';
-
- return MZ_TRUE;
-}
-
-mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index,
- char *pFilename, mz_uint filename_buf_size) {
- mz_uint n;
- const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
- if (!p) {
- if (filename_buf_size) pFilename[0] = '\0';
- return 0;
- }
- n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
- if (filename_buf_size) {
- n = MZ_MIN(n, filename_buf_size - 1);
- memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n);
- pFilename[n] = '\0';
- }
- return n + 1;
-}
-
-static MZ_FORCEINLINE mz_bool mz_zip_reader_string_equal(const char *pA,
- const char *pB,
- mz_uint len,
- mz_uint flags) {
- mz_uint i;
- if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) return 0 == memcmp(pA, pB, len);
- for (i = 0; i < len; ++i)
- if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) return MZ_FALSE;
- return MZ_TRUE;
-}
-
-static MZ_FORCEINLINE int mz_zip_reader_filename_compare(
- const mz_zip_array *pCentral_dir_array,
- const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR,
- mz_uint r_len) {
- const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(
- pCentral_dir_array, mz_uint8,
- MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32,
- l_index)),
- *pE;
- mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS);
- mz_uint8 l = 0, r = 0;
- pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
- pE = pL + MZ_MIN(l_len, r_len);
- while (pL < pE) {
- if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) break;
- pL++;
- pR++;
- }
- return (pL == pE) ? (int)(l_len - r_len) : (l - r);
-}
-
-static int mz_zip_reader_locate_file_binary_search(mz_zip_archive *pZip,
- const char *pFilename) {
- mz_zip_internal_state *pState = pZip->m_pState;
- const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets;
- const mz_zip_array *pCentral_dir = &pState->m_central_dir;
- mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(
- &pState->m_sorted_central_dir_offsets, mz_uint32, 0);
- const int size = pZip->m_total_files;
- const mz_uint filename_len = (mz_uint)strlen(pFilename);
- int l = 0, h = size - 1;
- while (l <= h) {
- int m = (l + h) >> 1, file_index = pIndices[m],
- comp =
- mz_zip_reader_filename_compare(pCentral_dir, pCentral_dir_offsets,
- file_index, pFilename, filename_len);
- if (!comp)
- return file_index;
- else if (comp < 0)
- l = m + 1;
- else
- h = m - 1;
- }
- return -1;
-}
-
-int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName,
- const char *pComment, mz_uint flags) {
- mz_uint file_index;
- size_t name_len, comment_len;
- if ((!pZip) || (!pZip->m_pState) || (!pName) ||
- (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
- return -1;
- if (((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) &&
- (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size))
- return mz_zip_reader_locate_file_binary_search(pZip, pName);
- name_len = strlen(pName);
- if (name_len > 0xFFFF) return -1;
- comment_len = pComment ? strlen(pComment) : 0;
- if (comment_len > 0xFFFF) return -1;
- for (file_index = 0; file_index < pZip->m_total_files; file_index++) {
- const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(
- &pZip->m_pState->m_central_dir, mz_uint8,
- MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32,
- file_index));
- mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS);
- const char *pFilename =
- (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
- if (filename_len < name_len) continue;
- if (comment_len) {
- mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS),
- file_comment_len =
- MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS);
- const char *pFile_comment = pFilename + filename_len + file_extra_len;
- if ((file_comment_len != comment_len) ||
- (!mz_zip_reader_string_equal(pComment, pFile_comment,
- file_comment_len, flags)))
- continue;
- }
- if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) {
- int ofs = filename_len - 1;
- do {
- if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') ||
- (pFilename[ofs] == ':'))
- break;
- } while (--ofs >= 0);
- ofs++;
- pFilename += ofs;
- filename_len -= ofs;
- }
- if ((filename_len == name_len) &&
- (mz_zip_reader_string_equal(pName, pFilename, filename_len, flags)))
- return file_index;
- }
- return -1;
-}
-
-mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip,
- mz_uint file_index, void *pBuf,
- size_t buf_size, mz_uint flags,
- void *pUser_read_buf,
- size_t user_read_buf_size) {
- int status = TINFL_STATUS_DONE;
- mz_uint64 needed_size, cur_file_ofs, comp_remaining,
- out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail;
- mz_zip_archive_file_stat file_stat;
- void *pRead_buf;
- mz_uint32
- local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
- sizeof(mz_uint32)];
- mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
- tinfl_decompressor inflator;
-
- if ((buf_size) && (!pBuf)) return MZ_FALSE;
-
- if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE;
-
- // Empty file, or a directory (but not always a directory - I've seen odd zips
- // with directories that have compressed data which inflates to 0 bytes)
- if (!file_stat.m_comp_size) return MZ_TRUE;
-
- // Entry is a subdirectory (I've seen old zips with dir entries which have
- // compressed deflate data which inflates to 0 bytes, but these entries claim
- // to uncompress to 512 bytes in the headers).
- // I'm torn how to handle this case - should it fail instead?
- if (mz_zip_reader_is_file_a_directory(pZip, file_index)) return MZ_TRUE;
-
- // Encryption and patch files are not supported.
- if (file_stat.m_bit_flag & (1 | 32)) return MZ_FALSE;
-
- // This function only supports stored and deflate.
- if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) &&
- (file_stat.m_method != MZ_DEFLATED))
- return MZ_FALSE;
-
- // Ensure supplied output buffer is large enough.
- needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size
- : file_stat.m_uncomp_size;
- if (buf_size < needed_size) return MZ_FALSE;
-
- // Read and parse the local directory entry.
- cur_file_ofs = file_stat.m_local_header_ofs;
- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header,
- MZ_ZIP_LOCAL_DIR_HEADER_SIZE) !=
- MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
- return MZ_FALSE;
- if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
- return MZ_FALSE;
-
- cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE +
- MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) +
- MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
- if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size)
- return MZ_FALSE;
-
- if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) {
- // The file is stored or the caller has requested the compressed data.
- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf,
- (size_t)needed_size) != needed_size)
- return MZ_FALSE;
- return ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) != 0) ||
- (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf,
- (size_t)file_stat.m_uncomp_size) == file_stat.m_crc32);
- }
-
- // Decompress the file either directly from memory or from a file input
- // buffer.
- tinfl_init(&inflator);
-
- if (pZip->m_pState->m_pMem) {
- // Read directly from the archive in memory.
- pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs;
- read_buf_size = read_buf_avail = file_stat.m_comp_size;
- comp_remaining = 0;
- } else if (pUser_read_buf) {
- // Use a user provided read buffer.
- if (!user_read_buf_size) return MZ_FALSE;
- pRead_buf = (mz_uint8 *)pUser_read_buf;
- read_buf_size = user_read_buf_size;
- read_buf_avail = 0;
- comp_remaining = file_stat.m_comp_size;
- } else {
- // Temporarily allocate a read buffer.
- read_buf_size =
- MZ_MIN(file_stat.m_comp_size, (mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE);
-#ifdef _MSC_VER
- if (((0, sizeof(size_t) == sizeof(mz_uint32))) &&
- (read_buf_size > 0x7FFFFFFF))
-#else
- if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF))
-#endif
- return MZ_FALSE;
- if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1,
- (size_t)read_buf_size)))
- return MZ_FALSE;
- read_buf_avail = 0;
- comp_remaining = file_stat.m_comp_size;
- }
-
- do {
- size_t in_buf_size,
- out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs);
- if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) {
- read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf,
- (size_t)read_buf_avail) != read_buf_avail) {
- status = TINFL_STATUS_FAILED;
- break;
- }
- cur_file_ofs += read_buf_avail;
- comp_remaining -= read_buf_avail;
- read_buf_ofs = 0;
- }
- in_buf_size = (size_t)read_buf_avail;
- status = tinfl_decompress(
- &inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size,
- (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size,
- TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF |
- (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0));
- read_buf_avail -= in_buf_size;
- read_buf_ofs += in_buf_size;
- out_buf_ofs += out_buf_size;
- } while (status == TINFL_STATUS_NEEDS_MORE_INPUT);
-
- if (status == TINFL_STATUS_DONE) {
- // Make sure the entire file was decompressed, and check its CRC.
- if ((out_buf_ofs != file_stat.m_uncomp_size) ||
- (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf,
- (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32))
- status = TINFL_STATUS_FAILED;
- }
-
- if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf))
- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
-
- return status == TINFL_STATUS_DONE;
-}
-
-mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(
- mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size,
- mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) {
- int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags);
- if (file_index < 0) return MZ_FALSE;
- return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size,
- flags, pUser_read_buf,
- user_read_buf_size);
-}
-
-mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index,
- void *pBuf, size_t buf_size,
- mz_uint flags) {
- return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size,
- flags, NULL, 0);
-}
-
-mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip,
- const char *pFilename, void *pBuf,
- size_t buf_size, mz_uint flags) {
- return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf,
- buf_size, flags, NULL, 0);
-}
-
-void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index,
- size_t *pSize, mz_uint flags) {
- mz_uint64 comp_size, uncomp_size, alloc_size;
- const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
- void *pBuf;
-
- if (pSize) *pSize = 0;
- if (!p) return NULL;
-
- comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
- uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
-
- alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size;
-#ifdef _MSC_VER
- if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF))
-#else
- if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF))
-#endif
- return NULL;
- if (NULL ==
- (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size)))
- return NULL;
-
- if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size,
- flags)) {
- pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
- return NULL;
- }
-
- if (pSize) *pSize = (size_t)alloc_size;
- return pBuf;
-}
-
-void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip,
- const char *pFilename, size_t *pSize,
- mz_uint flags) {
- int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags);
- if (file_index < 0) {
- if (pSize) *pSize = 0;
- return MZ_FALSE;
- }
- return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags);
-}
-
-mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip,
- mz_uint file_index,
- mz_file_write_func pCallback,
- void *pOpaque, mz_uint flags) {
- int status = TINFL_STATUS_DONE;
- mz_uint file_crc32 = MZ_CRC32_INIT;
- mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining,
- out_buf_ofs = 0, cur_file_ofs;
- mz_zip_archive_file_stat file_stat;
- void *pRead_buf = NULL;
- void *pWrite_buf = NULL;
- mz_uint32
- local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
- sizeof(mz_uint32)];
- mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
-
- if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE;
-
- // Empty file, or a directory (but not always a directory - I've seen odd zips
- // with directories that have compressed data which inflates to 0 bytes)
- if (!file_stat.m_comp_size) return MZ_TRUE;
-
- // Entry is a subdirectory (I've seen old zips with dir entries which have
- // compressed deflate data which inflates to 0 bytes, but these entries claim
- // to uncompress to 512 bytes in the headers).
- // I'm torn how to handle this case - should it fail instead?
- if (mz_zip_reader_is_file_a_directory(pZip, file_index)) return MZ_TRUE;
-
- // Encryption and patch files are not supported.
- if (file_stat.m_bit_flag & (1 | 32)) return MZ_FALSE;
-
- // This function only supports stored and deflate.
- if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) &&
- (file_stat.m_method != MZ_DEFLATED))
- return MZ_FALSE;
-
- // Read and parse the local directory entry.
- cur_file_ofs = file_stat.m_local_header_ofs;
- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header,
- MZ_ZIP_LOCAL_DIR_HEADER_SIZE) !=
- MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
- return MZ_FALSE;
- if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
- return MZ_FALSE;
-
- cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE +
- MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) +
- MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
- if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size)
- return MZ_FALSE;
-
- // Decompress the file either directly from memory or from a file input
- // buffer.
- if (pZip->m_pState->m_pMem) {
- pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs;
- read_buf_size = read_buf_avail = file_stat.m_comp_size;
- comp_remaining = 0;
- } else {
- read_buf_size =
- MZ_MIN(file_stat.m_comp_size, (mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE);
- if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1,
- (size_t)read_buf_size)))
- return MZ_FALSE;
- read_buf_avail = 0;
- comp_remaining = file_stat.m_comp_size;
- }
-
- if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) {
- // The file is stored or the caller has requested the compressed data.
- if (pZip->m_pState->m_pMem) {
-#ifdef _MSC_VER
- if (((0, sizeof(size_t) == sizeof(mz_uint32))) &&
- (file_stat.m_comp_size > 0xFFFFFFFF))
-#else
- if (((sizeof(size_t) == sizeof(mz_uint32))) &&
- (file_stat.m_comp_size > 0xFFFFFFFF))
-#endif
- return MZ_FALSE;
- if (pCallback(pOpaque, out_buf_ofs, pRead_buf,
- (size_t)file_stat.m_comp_size) != file_stat.m_comp_size)
- status = TINFL_STATUS_FAILED;
- else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
- file_crc32 =
- (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf,
- (size_t)file_stat.m_comp_size);
- cur_file_ofs += file_stat.m_comp_size;
- out_buf_ofs += file_stat.m_comp_size;
- comp_remaining = 0;
- } else {
- while (comp_remaining) {
- read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf,
- (size_t)read_buf_avail) != read_buf_avail) {
- status = TINFL_STATUS_FAILED;
- break;
- }
-
- if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
- file_crc32 = (mz_uint32)mz_crc32(
- file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail);
-
- if (pCallback(pOpaque, out_buf_ofs, pRead_buf,
- (size_t)read_buf_avail) != read_buf_avail) {
- status = TINFL_STATUS_FAILED;
- break;
- }
- cur_file_ofs += read_buf_avail;
- out_buf_ofs += read_buf_avail;
- comp_remaining -= read_buf_avail;
- }
- }
- } else {
- tinfl_decompressor inflator;
- tinfl_init(&inflator);
-
- if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1,
- TINFL_LZ_DICT_SIZE)))
- status = TINFL_STATUS_FAILED;
- else {
- do {
- mz_uint8 *pWrite_buf_cur =
- (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));
- size_t in_buf_size,
- out_buf_size =
- TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));
- if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) {
- read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf,
- (size_t)read_buf_avail) != read_buf_avail) {
- status = TINFL_STATUS_FAILED;
- break;
- }
- cur_file_ofs += read_buf_avail;
- comp_remaining -= read_buf_avail;
- read_buf_ofs = 0;
- }
-
- in_buf_size = (size_t)read_buf_avail;
- status = tinfl_decompress(
- &inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size,
- (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size,
- comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0);
- read_buf_avail -= in_buf_size;
- read_buf_ofs += in_buf_size;
-
- if (out_buf_size) {
- if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) !=
- out_buf_size) {
- status = TINFL_STATUS_FAILED;
- break;
- }
- file_crc32 =
- (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size);
- if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) {
- status = TINFL_STATUS_FAILED;
- break;
- }
- }
- } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) ||
- (status == TINFL_STATUS_HAS_MORE_OUTPUT));
- }
- }
-
- if ((status == TINFL_STATUS_DONE) &&
- (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) {
- // Make sure the entire file was decompressed, and check its CRC.
- if ((out_buf_ofs != file_stat.m_uncomp_size) ||
- (file_crc32 != file_stat.m_crc32))
- status = TINFL_STATUS_FAILED;
- }
-
- if (!pZip->m_pState->m_pMem) pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
- if (pWrite_buf) pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf);
-
- return status == TINFL_STATUS_DONE;
-}
-
-mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip,
- const char *pFilename,
- mz_file_write_func pCallback,
- void *pOpaque, mz_uint flags) {
- int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags);
- if (file_index < 0) return MZ_FALSE;
- return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque,
- flags);
-}
-
-#ifndef MINIZ_NO_STDIO
-static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs,
- const void *pBuf, size_t n) {
- (void)ofs;
- return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque);
-}
-
-mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index,
- const char *pDst_filename,
- mz_uint flags) {
- mz_bool status;
- mz_zip_archive_file_stat file_stat;
- MZ_FILE *pFile;
- if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE;
- pFile = MZ_FOPEN(pDst_filename, "wb");
- if (!pFile) return MZ_FALSE;
- status = mz_zip_reader_extract_to_callback(
- pZip, file_index, mz_zip_file_write_callback, pFile, flags);
- if (MZ_FCLOSE(pFile) == EOF) return MZ_FALSE;
-#ifndef MINIZ_NO_TIME
- if (status)
- mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time);
-#endif
- return status;
-}
-#endif // #ifndef MINIZ_NO_STDIO
-
-mz_bool mz_zip_reader_end(mz_zip_archive *pZip) {
- if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) ||
- (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
- return MZ_FALSE;
-
- if (pZip->m_pState) {
- mz_zip_internal_state *pState = pZip->m_pState;
- pZip->m_pState = NULL;
- mz_zip_array_clear(pZip, &pState->m_central_dir);
- mz_zip_array_clear(pZip, &pState->m_central_dir_offsets);
- mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets);
-
-#ifndef MINIZ_NO_STDIO
- if (pState->m_pFile) {
- MZ_FCLOSE(pState->m_pFile);
- pState->m_pFile = NULL;
- }
-#endif // #ifndef MINIZ_NO_STDIO
-
- pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
- }
- pZip->m_zip_mode = MZ_ZIP_MODE_INVALID;
-
- return MZ_TRUE;
-}
-
-#ifndef MINIZ_NO_STDIO
-mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip,
- const char *pArchive_filename,
- const char *pDst_filename,
- mz_uint flags) {
- int file_index =
- mz_zip_reader_locate_file(pZip, pArchive_filename, NULL, flags);
- if (file_index < 0) return MZ_FALSE;
- return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags);
-}
-#endif
-
-// ------------------- .ZIP archive writing
-
-#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
-
-static void mz_write_le16(mz_uint8 *p, mz_uint16 v) {
- p[0] = (mz_uint8)v;
- p[1] = (mz_uint8)(v >> 8);
-}
-static void mz_write_le32(mz_uint8 *p, mz_uint32 v) {
- p[0] = (mz_uint8)v;
- p[1] = (mz_uint8)(v >> 8);
- p[2] = (mz_uint8)(v >> 16);
- p[3] = (mz_uint8)(v >> 24);
-}
-#define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v))
-#define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v))
-
-mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) {
- if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) ||
- (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID))
- return MZ_FALSE;
-
- if (pZip->m_file_offset_alignment) {
- // Ensure user specified file offset alignment is a power of 2.
- if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1))
- return MZ_FALSE;
- }
-
- if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func;
- if (!pZip->m_pFree) pZip->m_pFree = def_free_func;
- if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func;
-
- pZip->m_zip_mode = MZ_ZIP_MODE_WRITING;
- pZip->m_archive_size = existing_size;
- pZip->m_central_directory_file_ofs = 0;
- pZip->m_total_files = 0;
-
- if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(
- pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state))))
- return MZ_FALSE;
- memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state));
- MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir,
- sizeof(mz_uint8));
- MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets,
- sizeof(mz_uint32));
- MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets,
- sizeof(mz_uint32));
- return MZ_TRUE;
-}
-
-static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs,
- const void *pBuf, size_t n) {
- mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
- mz_zip_internal_state *pState = pZip->m_pState;
- mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size);
-#ifdef _MSC_VER
- if ((!n) ||
- ((0, sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)))
-#else
- if ((!n) ||
- ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)))
-#endif
- return 0;
- if (new_size > pState->m_mem_capacity) {
- void *pNew_block;
- size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity);
- while (new_capacity < new_size) new_capacity *= 2;
- if (NULL == (pNew_block = pZip->m_pRealloc(
- pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity)))
- return 0;
- pState->m_pMem = pNew_block;
- pState->m_mem_capacity = new_capacity;
- }
- memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n);
- pState->m_mem_size = (size_t)new_size;
- return n;
-}
-
-mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip,
- size_t size_to_reserve_at_beginning,
- size_t initial_allocation_size) {
- pZip->m_pWrite = mz_zip_heap_write_func;
- pZip->m_pIO_opaque = pZip;
- if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) return MZ_FALSE;
- if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size,
- size_to_reserve_at_beginning))) {
- if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(
- pZip->m_pAlloc_opaque, 1, initial_allocation_size))) {
- mz_zip_writer_end(pZip);
- return MZ_FALSE;
- }
- pZip->m_pState->m_mem_capacity = initial_allocation_size;
- }
- return MZ_TRUE;
-}
-
-#ifndef MINIZ_NO_STDIO
-static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs,
- const void *pBuf, size_t n) {
- mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
- mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);
- if (((mz_int64)file_ofs < 0) ||
- (((cur_ofs != (mz_int64)file_ofs)) &&
- (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET))))
- return 0;
- return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile);
-}
-
-mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename,
- mz_uint64 size_to_reserve_at_beginning) {
- MZ_FILE *pFile;
- pZip->m_pWrite = mz_zip_file_write_func;
- pZip->m_pIO_opaque = pZip;
- if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) return MZ_FALSE;
- if (NULL == (pFile = MZ_FOPEN(pFilename, "wb"))) {
- mz_zip_writer_end(pZip);
- return MZ_FALSE;
- }
- pZip->m_pState->m_pFile = pFile;
- if (size_to_reserve_at_beginning) {
- mz_uint64 cur_ofs = 0;
- char buf[4096];
- MZ_CLEAR_OBJ(buf);
- do {
- size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning);
- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) {
- mz_zip_writer_end(pZip);
- return MZ_FALSE;
- }
- cur_ofs += n;
- size_to_reserve_at_beginning -= n;
- } while (size_to_reserve_at_beginning);
- }
- return MZ_TRUE;
-}
-#endif // #ifndef MINIZ_NO_STDIO
-
-mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip,
- const char *pFilename) {
- mz_zip_internal_state *pState;
- if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
- return MZ_FALSE;
- // No sense in trying to write to an archive that's already at the support max
- // size
- if ((pZip->m_total_files == 0xFFFF) ||
- ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
- MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > 0xFFFFFFFF))
- return MZ_FALSE;
-
- pState = pZip->m_pState;
-
- if (pState->m_pFile) {
-#ifdef MINIZ_NO_STDIO
- pFilename;
- return MZ_FALSE;
-#else
- // Archive is being read from stdio - try to reopen as writable.
- if (pZip->m_pIO_opaque != pZip) return MZ_FALSE;
- if (!pFilename) return MZ_FALSE;
- pZip->m_pWrite = mz_zip_file_write_func;
- if (NULL ==
- (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) {
- // The mz_zip_archive is now in a bogus state because pState->m_pFile is
- // NULL, so just close it.
- mz_zip_reader_end(pZip);
- return MZ_FALSE;
- }
-#endif // #ifdef MINIZ_NO_STDIO
- } else if (pState->m_pMem) {
- // Archive lives in a memory block. Assume it's from the heap that we can
- // resize using the realloc callback.
- if (pZip->m_pIO_opaque != pZip) return MZ_FALSE;
- pState->m_mem_capacity = pState->m_mem_size;
- pZip->m_pWrite = mz_zip_heap_write_func;
- }
- // Archive is being read via a user provided read function - make sure the
- // user has specified a write function too.
- else if (!pZip->m_pWrite)
- return MZ_FALSE;
-
- // Start writing new files at the archive's current central directory
- // location.
- pZip->m_archive_size = pZip->m_central_directory_file_ofs;
- pZip->m_zip_mode = MZ_ZIP_MODE_WRITING;
- pZip->m_central_directory_file_ofs = 0;
-
- return MZ_TRUE;
-}
-
-mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name,
- const void *pBuf, size_t buf_size,
- mz_uint level_and_flags) {
- return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0,
- level_and_flags, 0, 0);
-}
-
-typedef struct {
- mz_zip_archive *m_pZip;
- mz_uint64 m_cur_archive_file_ofs;
- mz_uint64 m_comp_size;
-} mz_zip_writer_add_state;
-
-static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len,
- void *pUser) {
- mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser;
- if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque,
- pState->m_cur_archive_file_ofs, pBuf,
- len) != len)
- return MZ_FALSE;
- pState->m_cur_archive_file_ofs += len;
- pState->m_comp_size += len;
- return MZ_TRUE;
-}
-
-static mz_bool mz_zip_writer_create_local_dir_header(
- mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size,
- mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size,
- mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags,
- mz_uint16 dos_time, mz_uint16 dos_date) {
- (void)pZip;
- memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE);
- MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG);
- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0);
- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags);
- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method);
- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time);
- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date);
- MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32);
- MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, comp_size);
- MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, uncomp_size);
- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size);
- MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size);
- return MZ_TRUE;
-}
-
-static mz_bool mz_zip_writer_create_central_dir_header(
- mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size,
- mz_uint16 extra_size, mz_uint16 comment_size, mz_uint64 uncomp_size,
- mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method,
- mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date,
- mz_uint64 local_header_ofs, mz_uint32 ext_attributes) {
- (void)pZip;
- memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE);
- MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG);
- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0);
- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags);
- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method);
- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time);
- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date);
- MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32);
- MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, comp_size);
- MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, uncomp_size);
- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size);
- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size);
- MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size);
- MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes);
- MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_header_ofs);
- return MZ_TRUE;
-}
-
-static mz_bool mz_zip_writer_add_to_central_dir(
- mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size,
- const void *pExtra, mz_uint16 extra_size, const void *pComment,
- mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size,
- mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags,
- mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs,
- mz_uint32 ext_attributes) {
- mz_zip_internal_state *pState = pZip->m_pState;
- mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size;
- size_t orig_central_dir_size = pState->m_central_dir.m_size;
- mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE];
-
- // No zip64 support yet
- if ((local_header_ofs > 0xFFFFFFFF) ||
- (((mz_uint64)pState->m_central_dir.m_size +
- MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size +
- comment_size) > 0xFFFFFFFF))
- return MZ_FALSE;
-
- if (!mz_zip_writer_create_central_dir_header(
- pZip, central_dir_header, filename_size, extra_size, comment_size,
- uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time,
- dos_date, local_header_ofs, ext_attributes))
- return MZ_FALSE;
-
- if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header,
- MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) ||
- (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename,
- filename_size)) ||
- (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra,
- extra_size)) ||
- (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment,
- comment_size)) ||
- (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets,
- &central_dir_ofs, 1))) {
- // Try to push the central directory array back into its original state.
- mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size,
- MZ_FALSE);
- return MZ_FALSE;
- }
-
- return MZ_TRUE;
-}
-
-static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) {
- // Basic ZIP archive filename validity checks: Valid filenames cannot start
- // with a forward slash, cannot contain a drive letter, and cannot use
- // DOS-style backward slashes.
- if (*pArchive_name == '/') return MZ_FALSE;
- while (*pArchive_name) {
- if ((*pArchive_name == '\\') || (*pArchive_name == ':')) return MZ_FALSE;
- pArchive_name++;
- }
- return MZ_TRUE;
-}
-
-static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(
- mz_zip_archive *pZip) {
- mz_uint32 n;
- if (!pZip->m_file_offset_alignment) return 0;
- n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1));
- return (pZip->m_file_offset_alignment - n) &
- (pZip->m_file_offset_alignment - 1);
-}
-
-static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip,
- mz_uint64 cur_file_ofs, mz_uint32 n) {
- char buf[4096];
- memset(buf, 0, MZ_MIN(sizeof(buf), n));
- while (n) {
- mz_uint32 s = MZ_MIN(sizeof(buf), n);
- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s)
- return MZ_FALSE;
- cur_file_ofs += s;
- n -= s;
- }
- return MZ_TRUE;
-}
-
-mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip,
- const char *pArchive_name, const void *pBuf,
- size_t buf_size, const void *pComment,
- mz_uint16 comment_size,
- mz_uint level_and_flags, mz_uint64 uncomp_size,
- mz_uint32 uncomp_crc32) {
- mz_uint16 method = 0, dos_time = 0, dos_date = 0;
- mz_uint level, ext_attributes = 0, num_alignment_padding_bytes;
- mz_uint64 local_dir_header_ofs = pZip->m_archive_size,
- cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0;
- size_t archive_name_size;
- mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];
- tdefl_compressor *pComp = NULL;
- mz_bool store_data_uncompressed;
- mz_zip_internal_state *pState;
-
- if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL;
- level = level_and_flags & 0xF;
- store_data_uncompressed =
- ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA));
-
- if ((!pZip) || (!pZip->m_pState) ||
- (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) ||
- (!pArchive_name) || ((comment_size) && (!pComment)) ||
- (pZip->m_total_files == 0xFFFF) || (level > MZ_UBER_COMPRESSION))
- return MZ_FALSE;
-
- pState = pZip->m_pState;
-
- if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size))
- return MZ_FALSE;
- // No zip64 support yet
- if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) return MZ_FALSE;
- if (!mz_zip_writer_validate_archive_name(pArchive_name)) return MZ_FALSE;
-
-#ifndef MINIZ_NO_TIME
- {
- time_t cur_time;
- time(&cur_time);
- mz_zip_time_to_dos_time(cur_time, &dos_time, &dos_date);
- }
-#endif // #ifndef MINIZ_NO_TIME
-
- archive_name_size = strlen(pArchive_name);
- if (archive_name_size > 0xFFFF) return MZ_FALSE;
-
- num_alignment_padding_bytes =
- mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
-
- // no zip64 support yet
- if ((pZip->m_total_files == 0xFFFF) ||
- ((pZip->m_archive_size + num_alignment_padding_bytes +
- MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
- comment_size + archive_name_size) > 0xFFFFFFFF))
- return MZ_FALSE;
-
- if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) {
- // Set DOS Subdirectory attribute bit.
- ext_attributes |= 0x10;
- // Subdirectories cannot contain data.
- if ((buf_size) || (uncomp_size)) return MZ_FALSE;
- }
-
- // Try to do any allocations before writing to the archive, so if an
- // allocation fails the file remains unmodified. (A good idea if we're doing
- // an in-place modification.)
- if ((!mz_zip_array_ensure_room(
- pZip, &pState->m_central_dir,
- MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size)) ||
- (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1)))
- return MZ_FALSE;
-
- if ((!store_data_uncompressed) && (buf_size)) {
- if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(
- pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor))))
- return MZ_FALSE;
- }
-
- if (!mz_zip_writer_write_zeros(
- pZip, cur_archive_file_ofs,
- num_alignment_padding_bytes + sizeof(local_dir_header))) {
- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
- return MZ_FALSE;
- }
- local_dir_header_ofs += num_alignment_padding_bytes;
- if (pZip->m_file_offset_alignment) {
- MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) ==
- 0);
- }
- cur_archive_file_ofs +=
- num_alignment_padding_bytes + sizeof(local_dir_header);
-
- MZ_CLEAR_OBJ(local_dir_header);
- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name,
- archive_name_size) != archive_name_size) {
- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
- return MZ_FALSE;
- }
- cur_archive_file_ofs += archive_name_size;
-
- if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) {
- uncomp_crc32 =
- (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size);
- uncomp_size = buf_size;
- if (uncomp_size <= 3) {
- level = 0;
- store_data_uncompressed = MZ_TRUE;
- }
- }
-
- if (store_data_uncompressed) {
- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf,
- buf_size) != buf_size) {
- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
- return MZ_FALSE;
- }
-
- cur_archive_file_ofs += buf_size;
- comp_size = buf_size;
-
- if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) method = MZ_DEFLATED;
- } else if (buf_size) {
- mz_zip_writer_add_state state;
-
- state.m_pZip = pZip;
- state.m_cur_archive_file_ofs = cur_archive_file_ofs;
- state.m_comp_size = 0;
-
- if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state,
- tdefl_create_comp_flags_from_zip_params(
- level, -15, MZ_DEFAULT_STRATEGY)) !=
- TDEFL_STATUS_OKAY) ||
- (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) !=
- TDEFL_STATUS_DONE)) {
- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
- return MZ_FALSE;
- }
-
- comp_size = state.m_comp_size;
- cur_archive_file_ofs = state.m_cur_archive_file_ofs;
-
- method = MZ_DEFLATED;
- }
-
- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
- pComp = NULL;
-
- // no zip64 support yet
- if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF))
- return MZ_FALSE;
-
- if (!mz_zip_writer_create_local_dir_header(
- pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size,
- comp_size, uncomp_crc32, method, 0, dos_time, dos_date))
- return MZ_FALSE;
-
- if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header,
- sizeof(local_dir_header)) != sizeof(local_dir_header))
- return MZ_FALSE;
-
- if (!mz_zip_writer_add_to_central_dir(
- pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment,
- comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0,
- dos_time, dos_date, local_dir_header_ofs, ext_attributes))
- return MZ_FALSE;
-
- pZip->m_total_files++;
- pZip->m_archive_size = cur_archive_file_ofs;
-
- return MZ_TRUE;
-}
-
-#ifndef MINIZ_NO_STDIO
-mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name,
- const char *pSrc_filename, const void *pComment,
- mz_uint16 comment_size,
- mz_uint level_and_flags) {
- mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes;
- mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0;
- mz_uint64 local_dir_header_ofs = pZip->m_archive_size,
- cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = 0,
- comp_size = 0;
- size_t archive_name_size;
- mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];
- MZ_FILE *pSrc_file = NULL;
-
- if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL;
- level = level_and_flags & 0xF;
-
- if ((!pZip) || (!pZip->m_pState) ||
- (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) ||
- ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION))
- return MZ_FALSE;
- if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) return MZ_FALSE;
- if (!mz_zip_writer_validate_archive_name(pArchive_name)) return MZ_FALSE;
-
- archive_name_size = strlen(pArchive_name);
- if (archive_name_size > 0xFFFF) return MZ_FALSE;
-
- num_alignment_padding_bytes =
- mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
-
- // no zip64 support yet
- if ((pZip->m_total_files == 0xFFFF) ||
- ((pZip->m_archive_size + num_alignment_padding_bytes +
- MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
- comment_size + archive_name_size) > 0xFFFFFFFF))
- return MZ_FALSE;
-
- if (!mz_zip_get_file_modified_time(pSrc_filename, &dos_time, &dos_date))
- return MZ_FALSE;
-
- pSrc_file = MZ_FOPEN(pSrc_filename, "rb");
- if (!pSrc_file) return MZ_FALSE;
- MZ_FSEEK64(pSrc_file, 0, SEEK_END);
- uncomp_size = MZ_FTELL64(pSrc_file);
- MZ_FSEEK64(pSrc_file, 0, SEEK_SET);
-
- if (uncomp_size > 0xFFFFFFFF) {
- // No zip64 support yet
- MZ_FCLOSE(pSrc_file);
- return MZ_FALSE;
- }
- if (uncomp_size <= 3) level = 0;
-
- if (!mz_zip_writer_write_zeros(
- pZip, cur_archive_file_ofs,
- num_alignment_padding_bytes + sizeof(local_dir_header))) {
- MZ_FCLOSE(pSrc_file);
- return MZ_FALSE;
- }
- local_dir_header_ofs += num_alignment_padding_bytes;
- if (pZip->m_file_offset_alignment) {
- MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) ==
- 0);
- }
- cur_archive_file_ofs +=
- num_alignment_padding_bytes + sizeof(local_dir_header);
-
- MZ_CLEAR_OBJ(local_dir_header);
- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name,
- archive_name_size) != archive_name_size) {
- MZ_FCLOSE(pSrc_file);
- return MZ_FALSE;
- }
- cur_archive_file_ofs += archive_name_size;
-
- if (uncomp_size) {
- mz_uint64 uncomp_remaining = uncomp_size;
- void *pRead_buf =
- pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE);
- if (!pRead_buf) {
- MZ_FCLOSE(pSrc_file);
- return MZ_FALSE;
- }
-
- if (!level) {
- while (uncomp_remaining) {
- mz_uint n =
- (mz_uint)MZ_MIN((mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining);
- if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) ||
- (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf,
- n) != n)) {
- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
- MZ_FCLOSE(pSrc_file);
- return MZ_FALSE;
- }
- uncomp_crc32 =
- (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n);
- uncomp_remaining -= n;
- cur_archive_file_ofs += n;
- }
- comp_size = uncomp_size;
- } else {
- mz_bool result = MZ_FALSE;
- mz_zip_writer_add_state state;
- tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(
- pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor));
- if (!pComp) {
- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
- MZ_FCLOSE(pSrc_file);
- return MZ_FALSE;
- }
-
- state.m_pZip = pZip;
- state.m_cur_archive_file_ofs = cur_archive_file_ofs;
- state.m_comp_size = 0;
-
- if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state,
- tdefl_create_comp_flags_from_zip_params(
- level, -15, MZ_DEFAULT_STRATEGY)) !=
- TDEFL_STATUS_OKAY) {
- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
- MZ_FCLOSE(pSrc_file);
- return MZ_FALSE;
- }
-
- for (;;) {
- size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining,
- (mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE);
- tdefl_status status;
-
- if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size)
- break;
-
- uncomp_crc32 = (mz_uint32)mz_crc32(
- uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size);
- uncomp_remaining -= in_buf_size;
-
- status = tdefl_compress_buffer(
- pComp, pRead_buf, in_buf_size,
- uncomp_remaining ? TDEFL_NO_FLUSH : TDEFL_FINISH);
- if (status == TDEFL_STATUS_DONE) {
- result = MZ_TRUE;
- break;
- } else if (status != TDEFL_STATUS_OKAY)
- break;
- }
-
- pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
-
- if (!result) {
- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
- MZ_FCLOSE(pSrc_file);
- return MZ_FALSE;
- }
-
- comp_size = state.m_comp_size;
- cur_archive_file_ofs = state.m_cur_archive_file_ofs;
-
- method = MZ_DEFLATED;
- }
-
- pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
- }
-
- MZ_FCLOSE(pSrc_file);
- pSrc_file = NULL;
-
- // no zip64 support yet
- if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF))
- return MZ_FALSE;
-
- if (!mz_zip_writer_create_local_dir_header(
- pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size,
- comp_size, uncomp_crc32, method, 0, dos_time, dos_date))
- return MZ_FALSE;
-
- if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header,
- sizeof(local_dir_header)) != sizeof(local_dir_header))
- return MZ_FALSE;
-
- if (!mz_zip_writer_add_to_central_dir(
- pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment,
- comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0,
- dos_time, dos_date, local_dir_header_ofs, ext_attributes))
- return MZ_FALSE;
-
- pZip->m_total_files++;
- pZip->m_archive_size = cur_archive_file_ofs;
-
- return MZ_TRUE;
-}
-#endif // #ifndef MINIZ_NO_STDIO
-
-mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip,
- mz_zip_archive *pSource_zip,
- mz_uint file_index) {
- mz_uint n, bit_flags, num_alignment_padding_bytes;
- mz_uint64 comp_bytes_remaining, local_dir_header_ofs;
- mz_uint64 cur_src_file_ofs, cur_dst_file_ofs;
- mz_uint32
- local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
- sizeof(mz_uint32)];
- mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
- mz_uint8 central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE];
- size_t orig_central_dir_size;
- mz_zip_internal_state *pState;
- void *pBuf;
- const mz_uint8 *pSrc_central_header;
-
- if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING))
- return MZ_FALSE;
- if (NULL ==
- (pSrc_central_header = mz_zip_reader_get_cdh(pSource_zip, file_index)))
- return MZ_FALSE;
- pState = pZip->m_pState;
-
- num_alignment_padding_bytes =
- mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
-
- // no zip64 support yet
- if ((pZip->m_total_files == 0xFFFF) ||
- ((pZip->m_archive_size + num_alignment_padding_bytes +
- MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) >
- 0xFFFFFFFF))
- return MZ_FALSE;
-
- cur_src_file_ofs =
- MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
- cur_dst_file_ofs = pZip->m_archive_size;
-
- if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs,
- pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) !=
- MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
- return MZ_FALSE;
- if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
- return MZ_FALSE;
- cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE;
-
- if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs,
- num_alignment_padding_bytes))
- return MZ_FALSE;
- cur_dst_file_ofs += num_alignment_padding_bytes;
- local_dir_header_ofs = cur_dst_file_ofs;
- if (pZip->m_file_offset_alignment) {
- MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) ==
- 0);
- }
-
- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header,
- MZ_ZIP_LOCAL_DIR_HEADER_SIZE) !=
- MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
- return MZ_FALSE;
- cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE;
-
- n = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) +
- MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
- comp_bytes_remaining =
- n + MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
-
- if (NULL == (pBuf = pZip->m_pAlloc(
- pZip->m_pAlloc_opaque, 1,
- (size_t)MZ_MAX(sizeof(mz_uint32) * 4,
- MZ_MIN((mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE,
- comp_bytes_remaining)))))
- return MZ_FALSE;
-
- while (comp_bytes_remaining) {
- n = (mz_uint)MZ_MIN((mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining);
- if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf,
- n) != n) {
- pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
- return MZ_FALSE;
- }
- cur_src_file_ofs += n;
-
- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) {
- pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
- return MZ_FALSE;
- }
- cur_dst_file_ofs += n;
-
- comp_bytes_remaining -= n;
- }
-
- bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS);
- if (bit_flags & 8) {
- // Copy data descriptor
- if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf,
- sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4) {
- pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
- return MZ_FALSE;
- }
-
- n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == 0x08074b50) ? 4 : 3);
- if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) {
- pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
- return MZ_FALSE;
- }
-
- cur_src_file_ofs += n;
- cur_dst_file_ofs += n;
- }
- pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
-
- // no zip64 support yet
- if (cur_dst_file_ofs > 0xFFFFFFFF) return MZ_FALSE;
-
- orig_central_dir_size = pState->m_central_dir.m_size;
-
- memcpy(central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE);
- MZ_WRITE_LE32(central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS,
- local_dir_header_ofs);
- if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_header,
- MZ_ZIP_CENTRAL_DIR_HEADER_SIZE))
- return MZ_FALSE;
-
- n = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
- MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS) +
- MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS);
- if (!mz_zip_array_push_back(
- pZip, &pState->m_central_dir,
- pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n)) {
- mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size,
- MZ_FALSE);
- return MZ_FALSE;
- }
-
- if (pState->m_central_dir.m_size > 0xFFFFFFFF) return MZ_FALSE;
- n = (mz_uint32)orig_central_dir_size;
- if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) {
- mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size,
- MZ_FALSE);
- return MZ_FALSE;
- }
-
- pZip->m_total_files++;
- pZip->m_archive_size = cur_dst_file_ofs;
-
- return MZ_TRUE;
-}
-
-mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) {
- mz_zip_internal_state *pState;
- mz_uint64 central_dir_ofs, central_dir_size;
- mz_uint8 hdr[MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE];
-
- if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING))
- return MZ_FALSE;
-
- pState = pZip->m_pState;
-
- // no zip64 support yet
- if ((pZip->m_total_files > 0xFFFF) ||
- ((pZip->m_archive_size + pState->m_central_dir.m_size +
- MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF))
- return MZ_FALSE;
-
- central_dir_ofs = 0;
- central_dir_size = 0;
- if (pZip->m_total_files) {
- // Write central directory
- central_dir_ofs = pZip->m_archive_size;
- central_dir_size = pState->m_central_dir.m_size;
- pZip->m_central_directory_file_ofs = central_dir_ofs;
- if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs,
- pState->m_central_dir.m_p,
- (size_t)central_dir_size) != central_dir_size)
- return MZ_FALSE;
- pZip->m_archive_size += central_dir_size;
- }
-
- // Write end of central directory record
- MZ_CLEAR_OBJ(hdr);
- MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS,
- MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG);
- MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS,
- pZip->m_total_files);
- MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files);
- MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, central_dir_size);
- MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, central_dir_ofs);
-
- if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr,
- sizeof(hdr)) != sizeof(hdr))
- return MZ_FALSE;
-#ifndef MINIZ_NO_STDIO
- if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) return MZ_FALSE;
-#endif // #ifndef MINIZ_NO_STDIO
-
- pZip->m_archive_size += sizeof(hdr);
-
- pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED;
- return MZ_TRUE;
-}
-
-mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf,
- size_t *pSize) {
- if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pSize)) return MZ_FALSE;
- if (pZip->m_pWrite != mz_zip_heap_write_func) return MZ_FALSE;
- if (!mz_zip_writer_finalize_archive(pZip)) return MZ_FALSE;
-
- *pBuf = pZip->m_pState->m_pMem;
- *pSize = pZip->m_pState->m_mem_size;
- pZip->m_pState->m_pMem = NULL;
- pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0;
- return MZ_TRUE;
-}
-
-mz_bool mz_zip_writer_end(mz_zip_archive *pZip) {
- mz_zip_internal_state *pState;
- mz_bool status = MZ_TRUE;
- if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) ||
- ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) &&
- (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED)))
- return MZ_FALSE;
-
- pState = pZip->m_pState;
- pZip->m_pState = NULL;
- mz_zip_array_clear(pZip, &pState->m_central_dir);
- mz_zip_array_clear(pZip, &pState->m_central_dir_offsets);
- mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets);
-
-#ifndef MINIZ_NO_STDIO
- if (pState->m_pFile) {
- MZ_FCLOSE(pState->m_pFile);
- pState->m_pFile = NULL;
- }
-#endif // #ifndef MINIZ_NO_STDIO
-
- if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) {
- pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem);
- pState->m_pMem = NULL;
- }
-
- pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
- pZip->m_zip_mode = MZ_ZIP_MODE_INVALID;
- return status;
-}
-
-#ifndef MINIZ_NO_STDIO
-mz_bool mz_zip_add_mem_to_archive_file_in_place(
- const char *pZip_filename, const char *pArchive_name, const void *pBuf,
- size_t buf_size, const void *pComment, mz_uint16 comment_size,
- mz_uint level_and_flags) {
- mz_bool status, created_new_archive = MZ_FALSE;
- mz_zip_archive zip_archive;
- struct MZ_FILE_STAT_STRUCT file_stat;
- MZ_CLEAR_OBJ(zip_archive);
- if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL;
- if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) ||
- ((comment_size) && (!pComment)) ||
- ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION))
- return MZ_FALSE;
- if (!mz_zip_writer_validate_archive_name(pArchive_name)) return MZ_FALSE;
- if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) {
- // Create a new archive.
- if (!mz_zip_writer_init_file(&zip_archive, pZip_filename, 0))
- return MZ_FALSE;
- created_new_archive = MZ_TRUE;
- } else {
- // Append to an existing archive.
- if (!mz_zip_reader_init_file(
- &zip_archive, pZip_filename,
- level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY))
- return MZ_FALSE;
- if (!mz_zip_writer_init_from_reader(&zip_archive, pZip_filename)) {
- mz_zip_reader_end(&zip_archive);
- return MZ_FALSE;
- }
- }
- status =
- mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size,
- pComment, comment_size, level_and_flags, 0, 0);
- // Always finalize, even if adding failed for some reason, so we have a valid
- // central directory. (This may not always succeed, but we can try.)
- if (!mz_zip_writer_finalize_archive(&zip_archive)) status = MZ_FALSE;
- if (!mz_zip_writer_end(&zip_archive)) status = MZ_FALSE;
- if ((!status) && (created_new_archive)) {
- // It's a new archive and something went wrong, so just delete it.
- int ignoredStatus = MZ_DELETE_FILE(pZip_filename);
- (void)ignoredStatus;
- }
- return status;
-}
-
-void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename,
- const char *pArchive_name,
- size_t *pSize, mz_uint flags) {
- int file_index;
- mz_zip_archive zip_archive;
- void *p = NULL;
-
- if (pSize) *pSize = 0;
-
- if ((!pZip_filename) || (!pArchive_name)) return NULL;
-
- MZ_CLEAR_OBJ(zip_archive);
- if (!mz_zip_reader_init_file(
- &zip_archive, pZip_filename,
- flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY))
- return NULL;
-
- if ((file_index = mz_zip_reader_locate_file(&zip_archive, pArchive_name, NULL,
- flags)) >= 0)
- p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags);
-
- mz_zip_reader_end(&zip_archive);
- return p;
-}
-
-#endif // #ifndef MINIZ_NO_STDIO
-
-#endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
-
-#endif // #ifndef MINIZ_NO_ARCHIVE_APIS
-
-#ifdef __cplusplus
-}
-#endif
-
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-
-#endif // MINIZ_HEADER_FILE_ONLY
-
-/*
- This is free and unencumbered software released into the public domain.
-
- Anyone is free to copy, modify, publish, use, compile, sell, or
- distribute this software, either in source code form or as a compiled
- binary, for any purpose, commercial or non-commercial, and by any
- means.
-
- In jurisdictions that recognize copyright laws, the author or authors
- of this software dedicate any and all copyright interest in the
- software to the public domain. We make this dedication for the benefit
- of the public at large and to the detriment of our heirs and
- successors. We intend this dedication to be an overt act of
- relinquishment in perpetuity of all present and future rights to this
- software under copyright law.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- OTHER DEALINGS IN THE SOFTWARE.
-
- For more information, please refer to <http://unlicense.org/>
-*/
-
-// ---------------------- end of miniz ----------------------------------------
-
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-
-} // namespace miniz
-#else
-
-// Reuse MINIZ_LITTE_ENDIAN macro
-
-#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || \
- defined(__i386) || defined(__i486__) || defined(__i486) || \
- defined(i386) || defined(__ia64__) || defined(__x86_64__)
-// MINIZ_X86_OR_X64_CPU is only used to help set the below macros.
-#define MINIZ_X86_OR_X64_CPU 1
-#endif
-
-#if defined(__sparcv9)
-// Big endian
-#else
-#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU
-// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian.
-#define MINIZ_LITTLE_ENDIAN 1
-#endif
-#endif
-
-#endif // TINYEXR_USE_MINIZ
-
// static bool IsBigEndian(void) {
// union {
// unsigned int i;
@@ -7079,7 +684,7 @@ static void cpy2(unsigned short *dst_val, const unsigned short *src_val) {
}
static void swap2(unsigned short *val) {
-#ifdef MINIZ_LITTLE_ENDIAN
+#ifdef TINYEXR_LITTLE_ENDIAN
(void)val;
#else
unsigned short tmp = *val;
@@ -7138,7 +743,7 @@ static void cpy4(float *dst_val, const float *src_val) {
#endif
static void swap4(unsigned int *val) {
-#ifdef MINIZ_LITTLE_ENDIAN
+#ifdef TINYEXR_LITTLE_ENDIAN
(void)val;
#else
unsigned int tmp = *val;
@@ -7153,7 +758,7 @@ static void swap4(unsigned int *val) {
}
static void swap4(int *val) {
-#ifdef MINIZ_LITTLE_ENDIAN
+#ifdef TINYEXR_LITTLE_ENDIAN
(void)val;
#else
int tmp = *val;
@@ -7168,7 +773,7 @@ static void swap4(int *val) {
}
static void swap4(float *val) {
-#ifdef MINIZ_LITTLE_ENDIAN
+#ifdef TINYEXR_LITTLE_ENDIAN
(void)val;
#else
float tmp = *val;
@@ -7199,7 +804,7 @@ static void cpy8(tinyexr::tinyexr_uint64 *dst_val, const tinyexr::tinyexr_uint64
#endif
static void swap8(tinyexr::tinyexr_uint64 *val) {
-#ifdef MINIZ_LITTLE_ENDIAN
+#ifdef TINYEXR_LITTLE_ENDIAN
(void)val;
#else
tinyexr::tinyexr_uint64 tmp = (*val);
@@ -7218,12 +823,11 @@ static void swap8(tinyexr::tinyexr_uint64 *val) {
}
// https://gist.github.com/rygorous/2156668
-// Reuse MINIZ_LITTLE_ENDIAN flag from miniz.
union FP32 {
unsigned int u;
float f;
struct {
-#if MINIZ_LITTLE_ENDIAN
+#if TINYEXR_LITTLE_ENDIAN
unsigned int Mantissa : 23;
unsigned int Exponent : 8;
unsigned int Sign : 1;
@@ -7243,7 +847,7 @@ union FP32 {
union FP16 {
unsigned short u;
struct {
-#if MINIZ_LITTLE_ENDIAN
+#if TINYEXR_LITTLE_ENDIAN
unsigned int Mantissa : 10;
unsigned int Exponent : 5;
unsigned int Sign : 1;
@@ -7351,7 +955,7 @@ static const char *ReadString(std::string *s, const char *ptr, size_t len) {
}
if (size_t(q - ptr) >= len) {
- (*s) = std::string();
+ (*s).clear();
return NULL;
}
@@ -7438,6 +1042,7 @@ static void WriteAttributeToMemory(std::vector<unsigned char> *out,
typedef struct {
std::string name; // less than 255 bytes long
int pixel_type;
+ int requested_pixel_type;
int x_sampling;
int y_sampling;
unsigned char p_linear;
@@ -7465,6 +1070,7 @@ struct HeaderInfo {
int chunk_count;
// Tiled format
+ int tiled; // Non-zero if the part is tiled.
int tile_size_x;
int tile_size_y;
int tile_level_mode;
@@ -7474,6 +1080,11 @@ struct HeaderInfo {
int compression_type;
+ // required for multi-part or non-image files
+ std::string name;
+ // required for multi-part or non-image files
+ std::string type;
+
void clear() {
channels.clear();
attributes.clear();
@@ -7495,6 +1106,7 @@ struct HeaderInfo {
chunk_count = 0;
// Tiled format
+ tiled = 0;
tile_size_x = 0;
tile_size_y = 0;
tile_level_mode = 0;
@@ -7502,6 +1114,9 @@ struct HeaderInfo {
header_len = 0;
compression_type = 0;
+
+ name.clear();
+ type.clear();
}
};
@@ -7558,7 +1173,7 @@ static void WriteChannelInfo(std::vector<unsigned char> &data,
// Calculate total size.
for (size_t c = 0; c < channels.size(); c++) {
- sz += strlen(channels[c].name.c_str()) + 1; // +1 for \0
+ sz += channels[c].name.length() + 1; // +1 for \0
sz += 16; // 4 * int
}
data.resize(sz + 1);
@@ -7566,12 +1181,12 @@ static void WriteChannelInfo(std::vector<unsigned char> &data,
unsigned char *p = &data.at(0);
for (size_t c = 0; c < channels.size(); c++) {
- memcpy(p, channels[c].name.c_str(), strlen(channels[c].name.c_str()));
- p += strlen(channels[c].name.c_str());
+ memcpy(p, channels[c].name.c_str(), channels[c].name.length());
+ p += channels[c].name.length();
(*p) = '\0';
p++;
- int pixel_type = channels[c].pixel_type;
+ int pixel_type = channels[c].requested_pixel_type;
int x_sampling = channels[c].x_sampling;
int y_sampling = channels[c].y_sampling;
tinyexr::swap4(&pixel_type);
@@ -7650,11 +1265,11 @@ static void CompressZip(unsigned char *dst,
// Compress the data using miniz
//
- miniz::mz_ulong outSize = miniz::mz_compressBound(src_size);
- int ret = miniz::mz_compress(
+ mz_ulong outSize = mz_compressBound(src_size);
+ int ret = mz_compress(
dst, &outSize, static_cast<const unsigned char *>(&tmpBuf.at(0)),
src_size);
- assert(ret == miniz::MZ_OK);
+ assert(ret == MZ_OK);
(void)ret;
compressedSize = outSize;
@@ -7687,8 +1302,8 @@ static bool DecompressZip(unsigned char *dst,
#if TINYEXR_USE_MINIZ
int ret =
- miniz::mz_uncompress(&tmpBuf.at(0), uncompressed_size, src, src_size);
- if (miniz::MZ_OK != ret) {
+ mz_uncompress(&tmpBuf.at(0), uncompressed_size, src, src_size);
+ if (MZ_OK != ret) {
return false;
}
#else
@@ -8989,7 +2604,8 @@ static bool getCode(int po, int rlc, long long &c, int &lc, const char *&in,
if (po == rlc) {
if (lc < 8) {
/* TinyEXR issue 78 */
- if ((in + 1) >= in_end) {
+ /* TinyEXR issue 160. in + 1 -> in */
+ if (in >= in_end) {
return false;
}
@@ -9332,7 +2948,7 @@ static bool CompressPiz(unsigned char *outPtr, unsigned int *outSize,
unsigned short minNonZero;
unsigned short maxNonZero;
-#if !MINIZ_LITTLE_ENDIAN
+#if !TINYEXR_LITTLE_ENDIAN
// @todo { PIZ compression on BigEndian architecture. }
assert(0);
return false;
@@ -9355,7 +2971,7 @@ static bool CompressPiz(unsigned char *outPtr, unsigned int *outSize,
// cd.ys = c.channel().ySampling;
size_t pixelSize = sizeof(int); // UINT and FLOAT
- if (channelInfo[c].pixel_type == TINYEXR_PIXELTYPE_HALF) {
+ if (channelInfo[c].requested_pixel_type == TINYEXR_PIXELTYPE_HALF) {
pixelSize = sizeof(short);
}
@@ -9445,10 +3061,10 @@ static bool CompressPiz(unsigned char *outPtr, unsigned int *outSize,
}
static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr,
- size_t tmpBufSize, size_t inLen, int num_channels,
+ size_t tmpBufSizeInBytes, size_t inLen, int num_channels,
const EXRChannelInfo *channels, int data_width,
int num_lines) {
- if (inLen == tmpBufSize) {
+ if (inLen == tmpBufSizeInBytes) {
// Data is not compressed(Issue 40).
memcpy(outPtr, inPtr, inLen);
return true;
@@ -9458,7 +3074,7 @@ static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr,
unsigned short minNonZero;
unsigned short maxNonZero;
-#if !MINIZ_LITTLE_ENDIAN
+#if !TINYEXR_LITTLE_ENDIAN
// @todo { PIZ compression on BigEndian architecture. }
assert(0);
return false;
@@ -9501,7 +3117,7 @@ static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr,
return false;
}
- std::vector<unsigned short> tmpBuffer(tmpBufSize);
+ std::vector<unsigned short> tmpBuffer(tmpBufSizeInBytes / sizeof(unsigned short));
hufUncompress(reinterpret_cast<const char *>(ptr), length, &tmpBuffer);
//
@@ -9543,7 +3159,7 @@ static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr,
// Expand the pixel data to their original range
//
- applyLut(lut.data(), &tmpBuffer.at(0), static_cast<int>(tmpBufSize));
+ applyLut(lut.data(), &tmpBuffer.at(0), static_cast<int>(tmpBufSizeInBytes / sizeof(unsigned short)));
for (int y = 0; y < num_lines; y++) {
for (size_t i = 0; i < channelData.size(); ++i) {
@@ -9802,6 +3418,9 @@ static bool CompressZfp(std::vector<unsigned char> *outBuf,
// -----------------------------------------------------------------
//
+// heuristics
+#define TINYEXR_DIMENSION_THRESHOLD (1024 * 8192)
+
// TODO(syoyo): Refactor function arguments.
static bool DecodePixelData(/* out */ unsigned char **out_images,
const int *requested_pixel_types,
@@ -10432,8 +4051,8 @@ static bool DecodeTiledPixelData(
const EXRAttribute *attributes, size_t num_channels,
const EXRChannelInfo *channels,
const std::vector<size_t> &channel_offset_list) {
- if (tile_size_x > data_width || tile_size_y > data_height ||
- tile_size_x * tile_offset_x > data_width ||
+ // Here, data_width and data_height are the dimensions of the current (sub)level.
+ if (tile_size_x * tile_offset_x > data_width ||
tile_size_y * tile_offset_y > data_height) {
return false;
}
@@ -10541,6 +4160,7 @@ static inline std::wstring UTF8ToWchar(const std::string &str) {
}
#endif
+
static int ParseEXRHeader(HeaderInfo *info, bool *empty_header,
const EXRVersion *version, std::string *err,
const unsigned char *buf, size_t size) {
@@ -10579,6 +4199,11 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header,
bool has_pixel_aspect_ratio = false;
bool has_screen_window_center = false;
bool has_screen_window_width = false;
+ bool has_name = false;
+ bool has_type = false;
+
+ info->name.clear();
+ info->type.clear();
info->data_window.min_x = 0;
info->data_window.min_y = 0;
@@ -10594,6 +4219,7 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header,
info->screen_window_width = -1.0f;
info->pixel_aspect_ratio = -1.0f;
+ info->tiled = 0;
info->tile_size_x = -1;
info->tile_size_y = -1;
info->tile_level_mode = -1;
@@ -10628,7 +4254,8 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header,
marker += marker_size;
size -= marker_size;
- if (version->tiled && attr_name.compare("tiles") == 0) {
+ // For a multipart file, the version field 9th bit is 0.
+ if ((version->tiled || version->multipart || version->non_image) && attr_name.compare("tiles") == 0) {
unsigned int x_size, y_size;
unsigned char tile_mode;
assert(data.size() == 9);
@@ -10652,7 +4279,7 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header,
// mode = levelMode + roundingMode * 16
info->tile_level_mode = tile_mode & 0x3;
info->tile_rounding_mode = (tile_mode >> 4) & 0x1;
-
+ info->tiled = 1;
} else if (attr_name.compare("compression") == 0) {
bool ok = false;
if (data[0] < TINYEXR_COMPRESSIONTYPE_PIZ) {
@@ -10771,6 +4398,22 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header,
memcpy(&info->chunk_count, &data.at(0), sizeof(int));
tinyexr::swap4(&info->chunk_count);
}
+ } else if (attr_name.compare("name") == 0) {
+ if (!data.empty() && data[0]) {
+ data.push_back(0);
+ size_t len = strlen(reinterpret_cast<const char*>(&data[0]));
+ info->name.resize(len);
+ info->name.assign(reinterpret_cast<const char*>(&data[0]), len);
+ has_name = true;
+ }
+ } else if (attr_name.compare("type") == 0) {
+ if (!data.empty() && data[0]) {
+ data.push_back(0);
+ size_t len = strlen(reinterpret_cast<const char*>(&data[0]));
+ info->type.resize(len);
+ info->type.assign(reinterpret_cast<const char*>(&data[0]), len);
+ has_type = true;
+ }
} else {
// Custom attribute(up to TINYEXR_MAX_CUSTOM_ATTRIBUTES)
if (info->attributes.size() < TINYEXR_MAX_CUSTOM_ATTRIBUTES) {
@@ -10835,6 +4478,17 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header,
<< std::endl;
}
+ if (version->multipart || version->non_image) {
+ if (!has_name) {
+ ss_err << "\"name\" attribute not found in the header."
+ << std::endl;
+ }
+ if (!has_type) {
+ ss_err << "\"type\" attribute not found in the header."
+ << std::endl;
+ }
+ }
+
if (!(ss_err.str().empty())) {
if (err) {
(*err) += ss_err.str();
@@ -10865,12 +4519,30 @@ static void ConvertHeader(EXRHeader *exr_header, const HeaderInfo &info) {
exr_header->data_window.max_y = info.data_window.max_y;
exr_header->line_order = info.line_order;
exr_header->compression_type = info.compression_type;
-
+ exr_header->tiled = info.tiled;
exr_header->tile_size_x = info.tile_size_x;
exr_header->tile_size_y = info.tile_size_y;
exr_header->tile_level_mode = info.tile_level_mode;
exr_header->tile_rounding_mode = info.tile_rounding_mode;
+ EXRSetNameAttr(exr_header, info.name.c_str());
+
+ if (!info.type.empty()) {
+ if (info.type == "scanlineimage") {
+ assert(!exr_header->tiled);
+ } else if (info.type == "tiledimage") {
+ assert(exr_header->tiled);
+ } else if (info.type == "deeptile") {
+ exr_header->non_image = 1;
+ assert(exr_header->tiled);
+ } else if (info.type == "deepscanline") {
+ exr_header->non_image = 1;
+ assert(!exr_header->tiled);
+ } else {
+ assert(false);
+ }
+ }
+
exr_header->num_channels = static_cast<int>(info.channels.size());
exr_header->channels = static_cast<EXRChannelInfo *>(malloc(
@@ -10932,8 +4604,216 @@ static void ConvertHeader(EXRHeader *exr_header, const HeaderInfo &info) {
exr_header->header_len = info.header_len;
}
+struct OffsetData {
+ OffsetData() : num_x_levels(0), num_y_levels(0) {}
+ std::vector<std::vector<std::vector <tinyexr::tinyexr_uint64> > > offsets;
+ int num_x_levels;
+ int num_y_levels;
+};
+
+int LevelIndex(int lx, int ly, int tile_level_mode, int num_x_levels) {
+ switch (tile_level_mode) {
+ case TINYEXR_TILE_ONE_LEVEL:
+ return 0;
+
+ case TINYEXR_TILE_MIPMAP_LEVELS:
+ return lx;
+
+ case TINYEXR_TILE_RIPMAP_LEVELS:
+ return lx + ly * num_x_levels;
+
+ default:
+ assert(false);
+ }
+ return 0;
+}
+
+static int LevelSize(int toplevel_size, int level, int tile_rounding_mode) {
+ assert(level >= 0);
+
+ int b = (int)(1u << (unsigned)level);
+ int level_size = toplevel_size / b;
+
+ if (tile_rounding_mode == TINYEXR_TILE_ROUND_UP && level_size * b < toplevel_size)
+ level_size += 1;
+
+ return std::max(level_size, 1);
+}
+
+static int DecodeTiledLevel(EXRImage* exr_image, const EXRHeader* exr_header,
+ const OffsetData& offset_data,
+ const std::vector<size_t>& channel_offset_list,
+ int pixel_data_size,
+ const unsigned char* head, const size_t size,
+ std::string* err) {
+ int num_channels = exr_header->num_channels;
+
+ int level_index = LevelIndex(exr_image->level_x, exr_image->level_y, exr_header->tile_level_mode, offset_data.num_x_levels);
+ int num_y_tiles = (int)offset_data.offsets[level_index].size();
+ assert(num_y_tiles);
+ int num_x_tiles = (int)offset_data.offsets[level_index][0].size();
+ assert(num_x_tiles);
+ int num_tiles = num_x_tiles * num_y_tiles;
+
+ int err_code = TINYEXR_SUCCESS;
+
+ enum {
+ EF_SUCCESS = 0,
+ EF_INVALID_DATA = 1,
+ EF_INSUFFICIENT_DATA = 2,
+ EF_FAILED_TO_DECODE = 4
+ };
+#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0)
+ std::atomic<unsigned> error_flag(EF_SUCCESS);
+#else
+ unsigned error_flag(EF_SUCCESS);
+#endif
+
+ // Although the spec says : "...the data window is subdivided into an array of smaller rectangles...",
+ // the IlmImf library allows the dimensions of the tile to be larger (or equal) than the dimensions of the data window.
+#if 0
+ if ((exr_header->tile_size_x > exr_image->width || exr_header->tile_size_y > exr_image->height) &&
+ exr_image->level_x == 0 && exr_image->level_y == 0) {
+ if (err) {
+ (*err) += "Failed to decode tile data.\n";
+ }
+ err_code = TINYEXR_ERROR_INVALID_DATA;
+ }
+#endif
+ exr_image->tiles = static_cast<EXRTile*>(
+ calloc(sizeof(EXRTile), static_cast<size_t>(num_tiles)));
+
+#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0)
+ std::vector<std::thread> workers;
+ std::atomic<int> tile_count(0);
+
+ int num_threads = std::max(1, int(std::thread::hardware_concurrency()));
+ if (num_threads > int(num_tiles)) {
+ num_threads = int(num_tiles);
+ }
+
+ for (int t = 0; t < num_threads; t++) {
+ workers.emplace_back(std::thread([&]()
+ {
+ int tile_idx = 0;
+ while ((tile_idx = tile_count++) < num_tiles) {
+
+#else
+#if TINYEXR_USE_OPENMP
+#pragma omp parallel for
+#endif
+ for (int tile_idx = 0; tile_idx < num_tiles; tile_idx++) {
+#endif
+ // Allocate memory for each tile.
+ exr_image->tiles[tile_idx].images = tinyexr::AllocateImage(
+ num_channels, exr_header->channels,
+ exr_header->requested_pixel_types, exr_header->tile_size_x,
+ exr_header->tile_size_y);
+
+ int x_tile = tile_idx % num_x_tiles;
+ int y_tile = tile_idx / num_x_tiles;
+ // 16 byte: tile coordinates
+ // 4 byte : data size
+ // ~ : data(uncompressed or compressed)
+ tinyexr::tinyexr_uint64 offset = offset_data.offsets[level_index][y_tile][x_tile];
+ if (offset + sizeof(int) * 5 > size) {
+ // Insufficient data size.
+ error_flag |= EF_INSUFFICIENT_DATA;
+ continue;
+ }
+
+ size_t data_size =
+ size_t(size - (offset + sizeof(int) * 5));
+ const unsigned char* data_ptr =
+ reinterpret_cast<const unsigned char*>(head + offset);
+
+ int tile_coordinates[4];
+ memcpy(tile_coordinates, data_ptr, sizeof(int) * 4);
+ tinyexr::swap4(&tile_coordinates[0]);
+ tinyexr::swap4(&tile_coordinates[1]);
+ tinyexr::swap4(&tile_coordinates[2]);
+ tinyexr::swap4(&tile_coordinates[3]);
+
+ if (tile_coordinates[2] != exr_image->level_x) {
+ // Invalid data.
+ error_flag |= EF_INVALID_DATA;
+ continue;
+ }
+ if (tile_coordinates[3] != exr_image->level_y) {
+ // Invalid data.
+ error_flag |= EF_INVALID_DATA;
+ continue;
+ }
+
+ int data_len;
+ memcpy(&data_len, data_ptr + 16,
+ sizeof(int)); // 16 = sizeof(tile_coordinates)
+ tinyexr::swap4(&data_len);
+
+ if (data_len < 2 || size_t(data_len) > data_size) {
+ // Insufficient data size.
+ error_flag |= EF_INSUFFICIENT_DATA;
+ continue;
+ }
+
+ // Move to data addr: 20 = 16 + 4;
+ data_ptr += 20;
+ bool ret = tinyexr::DecodeTiledPixelData(
+ exr_image->tiles[tile_idx].images,
+ &(exr_image->tiles[tile_idx].width),
+ &(exr_image->tiles[tile_idx].height),
+ exr_header->requested_pixel_types, data_ptr,
+ static_cast<size_t>(data_len), exr_header->compression_type,
+ exr_header->line_order,
+ exr_image->width, exr_image->height,
+ tile_coordinates[0], tile_coordinates[1], exr_header->tile_size_x,
+ exr_header->tile_size_y, static_cast<size_t>(pixel_data_size),
+ static_cast<size_t>(exr_header->num_custom_attributes),
+ exr_header->custom_attributes,
+ static_cast<size_t>(exr_header->num_channels),
+ exr_header->channels, channel_offset_list);
+
+ if (!ret) {
+ // Failed to decode tile data.
+ error_flag |= EF_FAILED_TO_DECODE;
+ }
+
+ exr_image->tiles[tile_idx].offset_x = tile_coordinates[0];
+ exr_image->tiles[tile_idx].offset_y = tile_coordinates[1];
+ exr_image->tiles[tile_idx].level_x = tile_coordinates[2];
+ exr_image->tiles[tile_idx].level_y = tile_coordinates[3];
+
+#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0)
+ }
+ }));
+ } // num_thread loop
+
+ for (auto& t : workers) {
+ t.join();
+ }
+
+#else
+ } // parallel for
+#endif
+
+ // Even in the event of an error, the reserved memory may be freed.
+ exr_image->num_channels = num_channels;
+ exr_image->num_tiles = static_cast<int>(num_tiles);
+
+ if (error_flag) err_code = TINYEXR_ERROR_INVALID_DATA;
+ if (err) {
+ if (error_flag & EF_INSUFFICIENT_DATA) {
+ (*err) += "Insufficient data length.\n";
+ }
+ if (error_flag & EF_FAILED_TO_DECODE) {
+ (*err) += "Failed to decode tile data.\n";
+ }
+ }
+ return err_code;
+}
+
static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
- const std::vector<tinyexr::tinyexr_uint64> &offsets,
+ const OffsetData& offset_data,
const unsigned char *head, const size_t size,
std::string *err) {
int num_channels = exr_header->num_channels;
@@ -10971,8 +4851,7 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
// Do not allow too large data_width and data_height. header invalid?
{
- const int threshold = 1024 * 8192; // heuristics
- if ((data_width > threshold) || (data_height > threshold)) {
+ if ((data_width > TINYEXR_DIMENSION_THRESHOLD) || (data_height > TINYEXR_DIMENSION_THRESHOLD)) {
if (err) {
std::stringstream ss;
ss << "data_with or data_height too large. data_width: " << data_width
@@ -10982,8 +4861,21 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
}
return TINYEXR_ERROR_INVALID_DATA;
}
+ if (exr_header->tiled) {
+ if ((exr_header->tile_size_x > TINYEXR_DIMENSION_THRESHOLD) || (exr_header->tile_size_y > TINYEXR_DIMENSION_THRESHOLD)) {
+ if (err) {
+ std::stringstream ss;
+ ss << "tile with or tile height too large. tile width: " << exr_header->tile_size_x
+ << ", "
+ << "tile height = " << exr_header->tile_size_y << std::endl;
+ (*err) += ss.str();
+ }
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
+ }
}
+ const std::vector<tinyexr::tinyexr_uint64>& offsets = offset_data.offsets[0][0];
size_t num_blocks = offsets.size();
std::vector<size_t> channel_offset_list;
@@ -10998,7 +4890,11 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
return TINYEXR_ERROR_INVALID_DATA;
}
- bool invalid_data = false; // TODO(LTE): Use atomic lock for MT safety.
+#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0)
+ std::atomic<bool> invalid_data(false);
+#else
+ bool invalid_data(false);
+#endif
if (exr_header->tiled) {
// value check
@@ -11019,136 +4915,60 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
}
return TINYEXR_ERROR_INVALID_HEADER;
}
-
- size_t num_tiles = offsets.size(); // = # of blocks
-
- exr_image->tiles = static_cast<EXRTile *>(
- calloc(sizeof(EXRTile), static_cast<size_t>(num_tiles)));
-
- int err_code = TINYEXR_SUCCESS;
-
-#if (__cplusplus > 199711L) && (TINYEXR_USE_THREAD > 0)
-
- std::vector<std::thread> workers;
- std::atomic<size_t> tile_count(0);
-
- int num_threads = std::max(1, int(std::thread::hardware_concurrency()));
- if (num_threads > int(num_tiles)) {
- num_threads = int(num_tiles);
- }
-
- for (int t = 0; t < num_threads; t++) {
- workers.emplace_back(std::thread([&]() {
- size_t tile_idx = 0;
- while ((tile_idx = tile_count++) < num_tiles) {
-
-#else
- for (size_t tile_idx = 0; tile_idx < num_tiles; tile_idx++) {
-#endif
- // Allocate memory for each tile.
- exr_image->tiles[tile_idx].images = tinyexr::AllocateImage(
- num_channels, exr_header->channels,
- exr_header->requested_pixel_types, exr_header->tile_size_x,
- exr_header->tile_size_y);
-
- // 16 byte: tile coordinates
- // 4 byte : data size
- // ~ : data(uncompressed or compressed)
- if (offsets[tile_idx] + sizeof(int) * 5 > size) {
- // TODO(LTE): atomic
- if (err) {
- (*err) += "Insufficient data size.\n";
- }
- err_code = TINYEXR_ERROR_INVALID_DATA;
- break;
- }
-
- size_t data_size =
- size_t(size - (offsets[tile_idx] + sizeof(int) * 5));
- const unsigned char *data_ptr =
- reinterpret_cast<const unsigned char *>(head + offsets[tile_idx]);
-
- int tile_coordinates[4];
- memcpy(tile_coordinates, data_ptr, sizeof(int) * 4);
- tinyexr::swap4(&tile_coordinates[0]);
- tinyexr::swap4(&tile_coordinates[1]);
- tinyexr::swap4(&tile_coordinates[2]);
- tinyexr::swap4(&tile_coordinates[3]);
-
- // @todo{ LoD }
- if (tile_coordinates[2] != 0) {
- err_code = TINYEXR_ERROR_UNSUPPORTED_FEATURE;
- break;
- }
- if (tile_coordinates[3] != 0) {
- err_code = TINYEXR_ERROR_UNSUPPORTED_FEATURE;
- break;
- }
-
- int data_len;
- memcpy(&data_len, data_ptr + 16,
- sizeof(int)); // 16 = sizeof(tile_coordinates)
- tinyexr::swap4(&data_len);
-
- if (data_len < 4 || size_t(data_len) > data_size) {
- // TODO(LTE): atomic
- if (err) {
- (*err) += "Insufficient data length.\n";
- }
- err_code = TINYEXR_ERROR_INVALID_DATA;
- break;
- }
-
- // Move to data addr: 20 = 16 + 4;
- data_ptr += 20;
-
- bool ret = tinyexr::DecodeTiledPixelData(
- exr_image->tiles[tile_idx].images,
- &(exr_image->tiles[tile_idx].width),
- &(exr_image->tiles[tile_idx].height),
- exr_header->requested_pixel_types, data_ptr,
- static_cast<size_t>(data_len), exr_header->compression_type,
- exr_header->line_order, data_width, data_height,
- tile_coordinates[0], tile_coordinates[1], exr_header->tile_size_x,
- exr_header->tile_size_y, static_cast<size_t>(pixel_data_size),
- static_cast<size_t>(exr_header->num_custom_attributes),
- exr_header->custom_attributes,
- static_cast<size_t>(exr_header->num_channels),
- exr_header->channels, channel_offset_list);
-
- if (!ret) {
- // TODO(LTE): atomic
- if (err) {
- (*err) += "Failed to decode tile data.\n";
- }
- err_code = TINYEXR_ERROR_INVALID_DATA;
+ if (exr_header->tile_level_mode != TINYEXR_TILE_RIPMAP_LEVELS) {
+ EXRImage* level_image = NULL;
+ for (int level = 0; level < offset_data.num_x_levels; ++level) {
+ if (!level_image) {
+ level_image = exr_image;
+ } else {
+ level_image->next_level = new EXRImage;
+ InitEXRImage(level_image->next_level);
+ level_image = level_image->next_level;
+ }
+ level_image->width =
+ LevelSize(exr_header->data_window.max_x - exr_header->data_window.min_x + 1, level, exr_header->tile_rounding_mode);
+ level_image->height =
+ LevelSize(exr_header->data_window.max_y - exr_header->data_window.min_y + 1, level, exr_header->tile_rounding_mode);
+ level_image->level_x = level;
+ level_image->level_y = level;
+
+ int ret = DecodeTiledLevel(level_image, exr_header,
+ offset_data,
+ channel_offset_list,
+ pixel_data_size,
+ head, size,
+ err);
+ if (ret != TINYEXR_SUCCESS) return ret;
+ }
+ } else {
+ EXRImage* level_image = NULL;
+ for (int level_y = 0; level_y < offset_data.num_y_levels; ++level_y)
+ for (int level_x = 0; level_x < offset_data.num_x_levels; ++level_x) {
+ if (!level_image) {
+ level_image = exr_image;
+ } else {
+ level_image->next_level = new EXRImage;
+ InitEXRImage(level_image->next_level);
+ level_image = level_image->next_level;
}
- exr_image->tiles[tile_idx].offset_x = tile_coordinates[0];
- exr_image->tiles[tile_idx].offset_y = tile_coordinates[1];
- exr_image->tiles[tile_idx].level_x = tile_coordinates[2];
- exr_image->tiles[tile_idx].level_y = tile_coordinates[3];
-
-#if (__cplusplus > 199711L) && (TINYEXR_USE_THREAD > 0)
+ level_image->width =
+ LevelSize(exr_header->data_window.max_x - exr_header->data_window.min_x + 1, level_x, exr_header->tile_rounding_mode);
+ level_image->height =
+ LevelSize(exr_header->data_window.max_y - exr_header->data_window.min_y + 1, level_y, exr_header->tile_rounding_mode);
+ level_image->level_x = level_x;
+ level_image->level_y = level_y;
+
+ int ret = DecodeTiledLevel(level_image, exr_header,
+ offset_data,
+ channel_offset_list,
+ pixel_data_size,
+ head, size,
+ err);
+ if (ret != TINYEXR_SUCCESS) return ret;
}
- }));
- } // num_thread loop
-
- for (auto &t : workers) {
- t.join();
}
-
-#else
- }
-#endif
-
- if (err_code != TINYEXR_SUCCESS) {
- return err_code;
- }
-
- exr_image->num_tiles = static_cast<int>(num_tiles);
} else { // scanline format
-
// Don't allow too large image(256GB * pixel_data_size or more). Workaround
// for #104.
size_t total_data_len =
@@ -11170,7 +4990,7 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
num_channels, exr_header->channels, exr_header->requested_pixel_types,
data_width, data_height);
-#if (__cplusplus > 199711L) && (TINYEXR_USE_THREAD > 0)
+#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0)
std::vector<std::thread> workers;
std::atomic<int> y_count(0);
@@ -11271,7 +5091,7 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
}
}
-#if (__cplusplus > 199711L) && (TINYEXR_USE_THREAD > 0)
+#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0)
}
}));
}
@@ -11286,7 +5106,6 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
if (invalid_data) {
if (err) {
- std::stringstream ss;
(*err) += "Invalid data found when decoding pixels.\n";
}
return TINYEXR_ERROR_INVALID_DATA;
@@ -11343,6 +5162,370 @@ static bool ReconstructLineOffsets(
return true;
}
+
+static int FloorLog2(unsigned x) {
+ //
+ // For x > 0, floorLog2(y) returns floor(log(x)/log(2)).
+ //
+ int y = 0;
+ while (x > 1) {
+ y += 1;
+ x >>= 1u;
+ }
+ return y;
+}
+
+
+static int CeilLog2(unsigned x) {
+ //
+ // For x > 0, ceilLog2(y) returns ceil(log(x)/log(2)).
+ //
+ int y = 0;
+ int r = 0;
+ while (x > 1) {
+ if (x & 1)
+ r = 1;
+
+ y += 1;
+ x >>= 1u;
+ }
+ return y + r;
+}
+
+static int RoundLog2(int x, int tile_rounding_mode) {
+ return (tile_rounding_mode == TINYEXR_TILE_ROUND_DOWN) ? FloorLog2(static_cast<unsigned>(x)) : CeilLog2(static_cast<unsigned>(x));
+}
+
+static int CalculateNumXLevels(const EXRHeader* exr_header) {
+ int min_x = exr_header->data_window.min_x;
+ int max_x = exr_header->data_window.max_x;
+ int min_y = exr_header->data_window.min_y;
+ int max_y = exr_header->data_window.max_y;
+
+ int num = 0;
+ switch (exr_header->tile_level_mode) {
+ case TINYEXR_TILE_ONE_LEVEL:
+
+ num = 1;
+ break;
+
+ case TINYEXR_TILE_MIPMAP_LEVELS:
+
+ {
+ int w = max_x - min_x + 1;
+ int h = max_y - min_y + 1;
+ num = RoundLog2(std::max(w, h), exr_header->tile_rounding_mode) + 1;
+ }
+ break;
+
+ case TINYEXR_TILE_RIPMAP_LEVELS:
+
+ {
+ int w = max_x - min_x + 1;
+ num = RoundLog2(w, exr_header->tile_rounding_mode) + 1;
+ }
+ break;
+
+ default:
+
+ assert(false);
+ }
+
+ return num;
+}
+
+static int CalculateNumYLevels(const EXRHeader* exr_header) {
+ int min_x = exr_header->data_window.min_x;
+ int max_x = exr_header->data_window.max_x;
+ int min_y = exr_header->data_window.min_y;
+ int max_y = exr_header->data_window.max_y;
+ int num = 0;
+
+ switch (exr_header->tile_level_mode) {
+ case TINYEXR_TILE_ONE_LEVEL:
+
+ num = 1;
+ break;
+
+ case TINYEXR_TILE_MIPMAP_LEVELS:
+
+ {
+ int w = max_x - min_x + 1;
+ int h = max_y - min_y + 1;
+ num = RoundLog2(std::max(w, h), exr_header->tile_rounding_mode) + 1;
+ }
+ break;
+
+ case TINYEXR_TILE_RIPMAP_LEVELS:
+
+ {
+ int h = max_y - min_y + 1;
+ num = RoundLog2(h, exr_header->tile_rounding_mode) + 1;
+ }
+ break;
+
+ default:
+
+ assert(false);
+ }
+
+ return num;
+}
+
+static void CalculateNumTiles(std::vector<int>& numTiles,
+ int toplevel_size,
+ int size,
+ int tile_rounding_mode) {
+ for (unsigned i = 0; i < numTiles.size(); i++) {
+ int l = LevelSize(toplevel_size, i, tile_rounding_mode);
+ assert(l <= std::numeric_limits<int>::max() - size + 1);
+
+ numTiles[i] = (l + size - 1) / size;
+ }
+}
+
+static void PrecalculateTileInfo(std::vector<int>& num_x_tiles,
+ std::vector<int>& num_y_tiles,
+ const EXRHeader* exr_header) {
+ int min_x = exr_header->data_window.min_x;
+ int max_x = exr_header->data_window.max_x;
+ int min_y = exr_header->data_window.min_y;
+ int max_y = exr_header->data_window.max_y;
+
+ int num_x_levels = CalculateNumXLevels(exr_header);
+ int num_y_levels = CalculateNumYLevels(exr_header);
+
+ num_x_tiles.resize(num_x_levels);
+ num_y_tiles.resize(num_y_levels);
+
+ CalculateNumTiles(num_x_tiles,
+ max_x - min_x + 1,
+ exr_header->tile_size_x,
+ exr_header->tile_rounding_mode);
+
+ CalculateNumTiles(num_y_tiles,
+ max_y - min_y + 1,
+ exr_header->tile_size_y,
+ exr_header->tile_rounding_mode);
+}
+
+static void InitSingleResolutionOffsets(OffsetData& offset_data, size_t num_blocks) {
+ offset_data.offsets.resize(1);
+ offset_data.offsets[0].resize(1);
+ offset_data.offsets[0][0].resize(num_blocks);
+ offset_data.num_x_levels = 1;
+ offset_data.num_y_levels = 1;
+}
+
+// Return sum of tile blocks.
+static int InitTileOffsets(OffsetData& offset_data,
+ const EXRHeader* exr_header,
+ const std::vector<int>& num_x_tiles,
+ const std::vector<int>& num_y_tiles) {
+ int num_tile_blocks = 0;
+ offset_data.num_x_levels = static_cast<int>(num_x_tiles.size());
+ offset_data.num_y_levels = static_cast<int>(num_y_tiles.size());
+ switch (exr_header->tile_level_mode) {
+ case TINYEXR_TILE_ONE_LEVEL:
+ case TINYEXR_TILE_MIPMAP_LEVELS:
+ assert(offset_data.num_x_levels == offset_data.num_y_levels);
+ offset_data.offsets.resize(offset_data.num_x_levels);
+
+ for (unsigned int l = 0; l < offset_data.offsets.size(); ++l) {
+ offset_data.offsets[l].resize(num_y_tiles[l]);
+
+ for (unsigned int dy = 0; dy < offset_data.offsets[l].size(); ++dy) {
+ offset_data.offsets[l][dy].resize(num_x_tiles[l]);
+ num_tile_blocks += num_x_tiles[l];
+ }
+ }
+ break;
+
+ case TINYEXR_TILE_RIPMAP_LEVELS:
+
+ offset_data.offsets.resize(static_cast<size_t>(offset_data.num_x_levels) * static_cast<size_t>(offset_data.num_y_levels));
+
+ for (int ly = 0; ly < offset_data.num_y_levels; ++ly) {
+ for (int lx = 0; lx < offset_data.num_x_levels; ++lx) {
+ int l = ly * offset_data.num_x_levels + lx;
+ offset_data.offsets[l].resize(num_y_tiles[ly]);
+
+ for (size_t dy = 0; dy < offset_data.offsets[l].size(); ++dy) {
+ offset_data.offsets[l][dy].resize(num_x_tiles[lx]);
+ num_tile_blocks += num_x_tiles[lx];
+ }
+ }
+ }
+ break;
+
+ default:
+ assert(false);
+ }
+ return num_tile_blocks;
+}
+
+static bool IsAnyOffsetsAreInvalid(const OffsetData& offset_data) {
+ for (unsigned int l = 0; l < offset_data.offsets.size(); ++l)
+ for (unsigned int dy = 0; dy < offset_data.offsets[l].size(); ++dy)
+ for (unsigned int dx = 0; dx < offset_data.offsets[l][dy].size(); ++dx)
+ if (reinterpret_cast<const tinyexr::tinyexr_int64&>(offset_data.offsets[l][dy][dx]) <= 0)
+ return true;
+
+ return false;
+}
+
+static bool isValidTile(const EXRHeader* exr_header,
+ const OffsetData& offset_data,
+ int dx, int dy, int lx, int ly) {
+ if (lx < 0 || ly < 0 || dx < 0 || dy < 0) return false;
+ int num_x_levels = offset_data.num_x_levels;
+ int num_y_levels = offset_data.num_y_levels;
+ switch (exr_header->tile_level_mode) {
+ case TINYEXR_TILE_ONE_LEVEL:
+
+ if (lx == 0 &&
+ ly == 0 &&
+ offset_data.offsets.size() > 0 &&
+ offset_data.offsets[0].size() > static_cast<size_t>(dy) &&
+ offset_data.offsets[0][dy].size() > static_cast<size_t>(dx)) {
+ return true;
+ }
+
+ break;
+
+ case TINYEXR_TILE_MIPMAP_LEVELS:
+
+ if (lx < num_x_levels &&
+ ly < num_y_levels &&
+ offset_data.offsets.size() > static_cast<size_t>(lx) &&
+ offset_data.offsets[lx].size() > static_cast<size_t>(dy) &&
+ offset_data.offsets[lx][dy].size() > static_cast<size_t>(dx)) {
+ return true;
+ }
+
+ break;
+
+ case TINYEXR_TILE_RIPMAP_LEVELS:
+ {
+ size_t idx = static_cast<size_t>(lx) + static_cast<size_t>(ly)* static_cast<size_t>(num_x_levels);
+ if (lx < num_x_levels &&
+ ly < num_y_levels &&
+ (offset_data.offsets.size() > idx) &&
+ offset_data.offsets[idx].size() > static_cast<size_t>(dy) &&
+ offset_data.offsets[idx][dy].size() > static_cast<size_t>(dx)) {
+ return true;
+ }
+ }
+
+ break;
+
+ default:
+
+ return false;
+ }
+
+ return false;
+}
+
+static void ReconstructTileOffsets(OffsetData& offset_data,
+ const EXRHeader* exr_header,
+ const unsigned char* head, const unsigned char* marker, const size_t /*size*/,
+ bool isMultiPartFile,
+ bool isDeep) {
+ int numXLevels = offset_data.num_x_levels;
+ for (unsigned int l = 0; l < offset_data.offsets.size(); ++l) {
+ for (unsigned int dy = 0; dy < offset_data.offsets[l].size(); ++dy) {
+ for (unsigned int dx = 0; dx < offset_data.offsets[l][dy].size(); ++dx) {
+ tinyexr::tinyexr_uint64 tileOffset = marker - head;
+
+ if (isMultiPartFile) {
+ //int partNumber;
+ marker += sizeof(int);
+ }
+
+ int tileX;
+ memcpy(&tileX, marker, sizeof(int));
+ tinyexr::swap4(&tileX);
+ marker += sizeof(int);
+
+ int tileY;
+ memcpy(&tileY, marker, sizeof(int));
+ tinyexr::swap4(&tileY);
+ marker += sizeof(int);
+
+ int levelX;
+ memcpy(&levelX, marker, sizeof(int));
+ tinyexr::swap4(&levelX);
+ marker += sizeof(int);
+
+ int levelY;
+ memcpy(&levelY, marker, sizeof(int));
+ tinyexr::swap4(&levelY);
+ marker += sizeof(int);
+
+ if (isDeep) {
+ tinyexr::tinyexr_int64 packed_offset_table_size;
+ memcpy(&packed_offset_table_size, marker, sizeof(tinyexr::tinyexr_int64));
+ tinyexr::swap8(reinterpret_cast<tinyexr::tinyexr_uint64*>(&packed_offset_table_size));
+ marker += sizeof(tinyexr::tinyexr_int64);
+
+ tinyexr::tinyexr_int64 packed_sample_size;
+ memcpy(&packed_sample_size, marker, sizeof(tinyexr::tinyexr_int64));
+ tinyexr::swap8(reinterpret_cast<tinyexr::tinyexr_uint64*>(&packed_sample_size));
+ marker += sizeof(tinyexr::tinyexr_int64);
+
+ // next Int64 is unpacked sample size - skip that too
+ marker += packed_offset_table_size + packed_sample_size + 8;
+
+ } else {
+
+ int dataSize;
+ memcpy(&dataSize, marker, sizeof(int));
+ tinyexr::swap4(&dataSize);
+ marker += sizeof(int);
+ marker += dataSize;
+ }
+
+ if (!isValidTile(exr_header, offset_data,
+ tileX, tileY, levelX, levelY))
+ return;
+
+ int level_idx = LevelIndex(levelX, levelY, exr_header->tile_level_mode, numXLevels);
+ offset_data.offsets[level_idx][tileY][tileX] = tileOffset;
+ }
+ }
+ }
+}
+
+// marker output is also
+static int ReadOffsets(OffsetData& offset_data,
+ const unsigned char* head,
+ const unsigned char*& marker,
+ const size_t size,
+ const char** err) {
+ for (unsigned int l = 0; l < offset_data.offsets.size(); ++l) {
+ for (unsigned int dy = 0; dy < offset_data.offsets[l].size(); ++dy) {
+ for (unsigned int dx = 0; dx < offset_data.offsets[l][dy].size(); ++dx) {
+ tinyexr::tinyexr_uint64 offset;
+ if ((marker + sizeof(tinyexr_uint64)) >= (head + size)) {
+ tinyexr::SetErrorMessage("Insufficient data size in offset table.", err);
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
+
+ memcpy(&offset, marker, sizeof(tinyexr::tinyexr_uint64));
+ tinyexr::swap8(&offset);
+ if (offset >= size) {
+ tinyexr::SetErrorMessage("Invalid offset value in DecodeEXRImage.", err);
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
+ marker += sizeof(tinyexr::tinyexr_uint64); // = 8
+ offset_data.offsets[l][dy][dx] = offset;
+ }
+ }
+ }
+ return TINYEXR_SUCCESS;
+}
+
static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header,
const unsigned char *head,
const unsigned char *marker, const size_t size,
@@ -11383,100 +5566,114 @@ static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header,
// Do not allow too large data_width and data_height. header invalid?
{
- const int threshold = 1024 * 8192; // heuristics
- if (data_width > threshold) {
+ if (data_width > TINYEXR_DIMENSION_THRESHOLD) {
tinyexr::SetErrorMessage("data width too large.", err);
return TINYEXR_ERROR_INVALID_DATA;
}
- if (data_height > threshold) {
+ if (data_height > TINYEXR_DIMENSION_THRESHOLD) {
tinyexr::SetErrorMessage("data height too large.", err);
return TINYEXR_ERROR_INVALID_DATA;
}
}
- // Read offset tables.
- size_t num_blocks = 0;
-
- if (exr_header->chunk_count > 0) {
- // Use `chunkCount` attribute.
- num_blocks = static_cast<size_t>(exr_header->chunk_count);
- } else if (exr_header->tiled) {
- // @todo { LoD }
- if (exr_header->tile_size_x > data_width || exr_header->tile_size_x < 1 ||
- exr_header->tile_size_y > data_height || exr_header->tile_size_y < 1) {
- tinyexr::SetErrorMessage("tile sizes are invalid.", err);
+ if (exr_header->tiled) {
+ if (exr_header->tile_size_x > TINYEXR_DIMENSION_THRESHOLD) {
+ tinyexr::SetErrorMessage("tile width too large.", err);
return TINYEXR_ERROR_INVALID_DATA;
}
-
- size_t num_x_tiles = static_cast<size_t>(data_width) /
- static_cast<size_t>(exr_header->tile_size_x);
- if (num_x_tiles * static_cast<size_t>(exr_header->tile_size_x) <
- static_cast<size_t>(data_width)) {
- num_x_tiles++;
+ if (exr_header->tile_size_y > TINYEXR_DIMENSION_THRESHOLD) {
+ tinyexr::SetErrorMessage("tile height too large.", err);
+ return TINYEXR_ERROR_INVALID_DATA;
}
- size_t num_y_tiles = static_cast<size_t>(data_height) /
- static_cast<size_t>(exr_header->tile_size_y);
- if (num_y_tiles * static_cast<size_t>(exr_header->tile_size_y) <
- static_cast<size_t>(data_height)) {
- num_y_tiles++;
+ }
+
+ // Read offset tables.
+ OffsetData offset_data;
+ size_t num_blocks = 0;
+ // For a multi-resolution image, the size of the offset table will be calculated from the other attributes of the header.
+ // If chunk_count > 0 then chunk_count must be equal to the calculated tile count.
+ if (exr_header->tiled) {
+ {
+ std::vector<int> num_x_tiles, num_y_tiles;
+ PrecalculateTileInfo(num_x_tiles, num_y_tiles, exr_header);
+ num_blocks = InitTileOffsets(offset_data, exr_header, num_x_tiles, num_y_tiles);
+ if (exr_header->chunk_count > 0) {
+ if (exr_header->chunk_count != static_cast<int>(num_blocks)) {
+ tinyexr::SetErrorMessage("Invalid offset table size.", err);
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
+ }
}
- num_blocks = num_x_tiles * num_y_tiles;
+ int ret = ReadOffsets(offset_data, head, marker, size, err);
+ if (ret != TINYEXR_SUCCESS) return ret;
+ if (IsAnyOffsetsAreInvalid(offset_data)) {
+ ReconstructTileOffsets(offset_data, exr_header,
+ head, marker, size,
+ exr_header->multipart, exr_header->non_image);
+ }
+ } else if (exr_header->chunk_count > 0) {
+ // Use `chunkCount` attribute.
+ num_blocks = static_cast<size_t>(exr_header->chunk_count);
+ InitSingleResolutionOffsets(offset_data, num_blocks);
} else {
num_blocks = static_cast<size_t>(data_height) /
- static_cast<size_t>(num_scanline_blocks);
+ static_cast<size_t>(num_scanline_blocks);
if (num_blocks * static_cast<size_t>(num_scanline_blocks) <
- static_cast<size_t>(data_height)) {
+ static_cast<size_t>(data_height)) {
num_blocks++;
}
- }
-
- std::vector<tinyexr::tinyexr_uint64> offsets(num_blocks);
-
- for (size_t y = 0; y < num_blocks; y++) {
- tinyexr::tinyexr_uint64 offset;
- // Issue #81
- if ((marker + sizeof(tinyexr_uint64)) >= (head + size)) {
- tinyexr::SetErrorMessage("Insufficient data size in offset table.", err);
- return TINYEXR_ERROR_INVALID_DATA;
- }
- memcpy(&offset, marker, sizeof(tinyexr::tinyexr_uint64));
- tinyexr::swap8(&offset);
- if (offset >= size) {
- tinyexr::SetErrorMessage("Invalid offset value in DecodeEXRImage.", err);
- return TINYEXR_ERROR_INVALID_DATA;
- }
- marker += sizeof(tinyexr::tinyexr_uint64); // = 8
- offsets[y] = offset;
+ InitSingleResolutionOffsets(offset_data, num_blocks);
}
- // If line offsets are invalid, we try to reconstruct it.
- // See OpenEXR/IlmImf/ImfScanLineInputFile.cpp::readLineOffsets() for details.
- for (size_t y = 0; y < num_blocks; y++) {
- if (offsets[y] <= 0) {
- // TODO(syoyo) Report as warning?
- // if (err) {
- // stringstream ss;
- // ss << "Incomplete lineOffsets." << std::endl;
- // (*err) += ss.str();
- //}
- bool ret =
+ if (!exr_header->tiled) {
+ std::vector<tinyexr::tinyexr_uint64>& offsets = offset_data.offsets[0][0];
+ for (size_t y = 0; y < num_blocks; y++) {
+ tinyexr::tinyexr_uint64 offset;
+ // Issue #81
+ if ((marker + sizeof(tinyexr_uint64)) >= (head + size)) {
+ tinyexr::SetErrorMessage("Insufficient data size in offset table.", err);
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
+
+ memcpy(&offset, marker, sizeof(tinyexr::tinyexr_uint64));
+ tinyexr::swap8(&offset);
+ if (offset >= size) {
+ tinyexr::SetErrorMessage("Invalid offset value in DecodeEXRImage.", err);
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
+ marker += sizeof(tinyexr::tinyexr_uint64); // = 8
+ offsets[y] = offset;
+ }
+
+ // If line offsets are invalid, we try to reconstruct it.
+ // See OpenEXR/IlmImf/ImfScanLineInputFile.cpp::readLineOffsets() for details.
+ for (size_t y = 0; y < num_blocks; y++) {
+ if (offsets[y] <= 0) {
+ // TODO(syoyo) Report as warning?
+ // if (err) {
+ // stringstream ss;
+ // ss << "Incomplete lineOffsets." << std::endl;
+ // (*err) += ss.str();
+ //}
+ bool ret =
ReconstructLineOffsets(&offsets, num_blocks, head, marker, size);
- if (ret) {
- // OK
- break;
- } else {
- tinyexr::SetErrorMessage(
+ if (ret) {
+ // OK
+ break;
+ } else {
+ tinyexr::SetErrorMessage(
"Cannot reconstruct lineOffset table in DecodeEXRImage.", err);
- return TINYEXR_ERROR_INVALID_DATA;
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
}
}
}
{
std::string e;
- int ret = DecodeChunk(exr_image, exr_header, offsets, head, size, &e);
+ int ret = DecodeChunk(exr_image, exr_header, offset_data, head, size, &e);
if (ret != TINYEXR_SUCCESS) {
if (!e.empty()) {
@@ -11530,7 +5727,7 @@ struct LayerChannel {
};
static void ChannelsInLayer(const EXRHeader &exr_header,
- const std::string layer_name,
+ const std::string &layer_name,
std::vector<LayerChannel> &channels) {
channels.clear();
for (int c = 0; c < exr_header.num_channels; c++) {
@@ -11881,8 +6078,8 @@ int ParseEXRHeaderFromMemory(EXRHeader *exr_header, const EXRVersion *version,
ConvertHeader(exr_header, info);
- // transfoer `tiled` from version.
- exr_header->tiled = version->tiled;
+ exr_header->multipart = version->multipart ? 1 : 0;
+ exr_header->non_image = version->non_image ? 1 : 0;
return ret;
}
@@ -12087,7 +6284,7 @@ int LoadEXRImageFromFile(EXRImage *exr_image, const EXRHeader *exr_header,
FILE *fp = NULL;
#ifdef _WIN32
-#if defined(_MSC_VER) || defined(__MINGW32__) // MSVC, MinGW gcc or clang
+#if defined(_MSC_VER) || (defined(MINGW_HAS_SECURE_API) && MINGW_HAS_SECURE_API) // MSVC, MinGW GCC, or Clang.
errno_t errcode =
_wfopen_s(&fp, tinyexr::UTF8ToWchar(filename).c_str(), L"rb");
if (errcode != 0) {
@@ -12096,7 +6293,7 @@ int LoadEXRImageFromFile(EXRImage *exr_image, const EXRHeader *exr_header,
return TINYEXR_ERROR_CANT_OPEN_FILE;
}
#else
- // Unknown compiler
+ // Unknown compiler or MinGW without MINGW_HAS_SECURE_API.
fp = fopen(filename, "rb");
#endif
#else
@@ -12155,207 +6352,400 @@ int LoadEXRImageFromMemory(EXRImage *exr_image, const EXRHeader *exr_header,
err);
}
-size_t SaveEXRImageToMemory(const EXRImage *exr_image,
- const EXRHeader *exr_header,
- unsigned char **memory_out, const char **err) {
- if (exr_image == NULL || memory_out == NULL ||
- exr_header->compression_type < 0) {
- tinyexr::SetErrorMessage("Invalid argument for SaveEXRImageToMemory", err);
- return 0;
- }
+namespace tinyexr
+{
-#if !TINYEXR_USE_PIZ
- if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
- tinyexr::SetErrorMessage("PIZ compression is not supported in this build",
- err);
- return 0;
- }
-#endif
+// out_data must be allocated initially with the block-header size
+// of the current image(-part) type
+static bool EncodePixelData(/* out */ std::vector<unsigned char>& out_data,
+ const unsigned char* const* images,
+ int compression_type,
+ int /*line_order*/,
+ int width, // for tiled : tile.width
+ int /*height*/, // for tiled : header.tile_size_y
+ int x_stride, // for tiled : header.tile_size_x
+ int line_no, // for tiled : 0
+ int num_lines, // for tiled : tile.height
+ size_t pixel_data_size,
+ const std::vector<ChannelInfo>& channels,
+ const std::vector<size_t>& channel_offset_list,
+ const void* compression_param = 0) // zfp compression param
+{
+ size_t buf_size = static_cast<size_t>(width) *
+ static_cast<size_t>(num_lines) *
+ static_cast<size_t>(pixel_data_size);
+ //int last2bit = (buf_size & 3);
+ // buf_size must be multiple of four
+ //if(last2bit) buf_size += 4 - last2bit;
+ std::vector<unsigned char> buf(buf_size);
-#if !TINYEXR_USE_ZFP
- if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
- tinyexr::SetErrorMessage("ZFP compression is not supported in this build",
- err);
- return 0;
- }
-#endif
+ size_t start_y = static_cast<size_t>(line_no);
+ for (size_t c = 0; c < channels.size(); c++) {
+ if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) {
+ if (channels[c].requested_pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
+ for (int y = 0; y < num_lines; y++) {
+ // Assume increasing Y
+ float *line_ptr = reinterpret_cast<float *>(&buf.at(
+ static_cast<size_t>(pixel_data_size * y * width) +
+ channel_offset_list[c] *
+ static_cast<size_t>(width)));
+ for (int x = 0; x < width; x++) {
+ tinyexr::FP16 h16;
+ h16.u = reinterpret_cast<const unsigned short * const *>(
+ images)[c][(y + start_y) * x_stride + x];
-#if TINYEXR_USE_ZFP
- for (size_t i = 0; i < static_cast<size_t>(exr_header->num_channels); i++) {
- if (exr_header->requested_pixel_types[i] != TINYEXR_PIXELTYPE_FLOAT) {
- tinyexr::SetErrorMessage("Pixel type must be FLOAT for ZFP compression",
- err);
- return 0;
+ tinyexr::FP32 f32 = half_to_float(h16);
+
+ tinyexr::swap4(&f32.f);
+
+ // line_ptr[x] = f32.f;
+ tinyexr::cpy4(line_ptr + x, &(f32.f));
+ }
+ }
+ } else if (channels[c].requested_pixel_type == TINYEXR_PIXELTYPE_HALF) {
+ for (int y = 0; y < num_lines; y++) {
+ // Assume increasing Y
+ unsigned short *line_ptr = reinterpret_cast<unsigned short *>(
+ &buf.at(static_cast<size_t>(pixel_data_size * y *
+ width) +
+ channel_offset_list[c] *
+ static_cast<size_t>(width)));
+ for (int x = 0; x < width; x++) {
+ unsigned short val = reinterpret_cast<const unsigned short * const *>(
+ images)[c][(y + start_y) * x_stride + x];
+
+ tinyexr::swap2(&val);
+
+ // line_ptr[x] = val;
+ tinyexr::cpy2(line_ptr + x, &val);
+ }
+ }
+ } else {
+ assert(0);
+ }
+
+ } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
+ if (channels[c].requested_pixel_type == TINYEXR_PIXELTYPE_HALF) {
+ for (int y = 0; y < num_lines; y++) {
+ // Assume increasing Y
+ unsigned short *line_ptr = reinterpret_cast<unsigned short *>(
+ &buf.at(static_cast<size_t>(pixel_data_size * y *
+ width) +
+ channel_offset_list[c] *
+ static_cast<size_t>(width)));
+ for (int x = 0; x < width; x++) {
+ tinyexr::FP32 f32;
+ f32.f = reinterpret_cast<const float * const *>(
+ images)[c][(y + start_y) * x_stride + x];
+
+ tinyexr::FP16 h16;
+ h16 = float_to_half_full(f32);
+
+ tinyexr::swap2(reinterpret_cast<unsigned short *>(&h16.u));
+
+ // line_ptr[x] = h16.u;
+ tinyexr::cpy2(line_ptr + x, &(h16.u));
+ }
+ }
+ } else if (channels[c].requested_pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
+ for (int y = 0; y < num_lines; y++) {
+ // Assume increasing Y
+ float *line_ptr = reinterpret_cast<float *>(&buf.at(
+ static_cast<size_t>(pixel_data_size * y * width) +
+ channel_offset_list[c] *
+ static_cast<size_t>(width)));
+ for (int x = 0; x < width; x++) {
+ float val = reinterpret_cast<const float * const *>(
+ images)[c][(y + start_y) * x_stride + x];
+
+ tinyexr::swap4(&val);
+
+ // line_ptr[x] = val;
+ tinyexr::cpy4(line_ptr + x, &val);
+ }
+ }
+ } else {
+ assert(0);
+ }
+ } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) {
+ for (int y = 0; y < num_lines; y++) {
+ // Assume increasing Y
+ unsigned int *line_ptr = reinterpret_cast<unsigned int *>(&buf.at(
+ static_cast<size_t>(pixel_data_size * y * width) +
+ channel_offset_list[c] * static_cast<size_t>(width)));
+ for (int x = 0; x < width; x++) {
+ unsigned int val = reinterpret_cast<const unsigned int * const *>(
+ images)[c][(y + start_y) * x_stride + x];
+
+ tinyexr::swap4(&val);
+
+ // line_ptr[x] = val;
+ tinyexr::cpy4(line_ptr + x, &val);
+ }
+ }
}
}
+
+ if (compression_type == TINYEXR_COMPRESSIONTYPE_NONE) {
+ // 4 byte: scan line
+ // 4 byte: data size
+ // ~ : pixel data(uncompressed)
+ out_data.insert(out_data.end(), buf.begin(), buf.end());
+
+ } else if ((compression_type == TINYEXR_COMPRESSIONTYPE_ZIPS) ||
+ (compression_type == TINYEXR_COMPRESSIONTYPE_ZIP)) {
+#if TINYEXR_USE_MINIZ
+ std::vector<unsigned char> block(mz_compressBound(
+ static_cast<unsigned long>(buf.size())));
+#else
+ std::vector<unsigned char> block(
+ compressBound(static_cast<uLong>(buf.size())));
#endif
+ tinyexr::tinyexr_uint64 outSize = block.size();
- std::vector<unsigned char> memory;
+ tinyexr::CompressZip(&block.at(0), outSize,
+ reinterpret_cast<const unsigned char *>(&buf.at(0)),
+ static_cast<unsigned long>(buf.size()));
- // Header
- {
- const char header[] = {0x76, 0x2f, 0x31, 0x01};
- memory.insert(memory.end(), header, header + 4);
- }
+ // 4 byte: scan line
+ // 4 byte: data size
+ // ~ : pixel data(compressed)
+ unsigned int data_len = static_cast<unsigned int>(outSize); // truncate
- // Version, scanline.
- {
- char marker[] = {2, 0, 0, 0};
- /* @todo
- if (exr_header->tiled) {
- marker[1] |= 0x2;
- }
- if (exr_header->long_name) {
- marker[1] |= 0x4;
- }
- if (exr_header->non_image) {
- marker[1] |= 0x8;
- }
- if (exr_header->multipart) {
- marker[1] |= 0x10;
- }
- */
- memory.insert(memory.end(), marker, marker + 4);
- }
+ out_data.insert(out_data.end(), block.begin(), block.begin() + data_len);
- int num_scanlines = 1;
- if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) {
- num_scanlines = 16;
- } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
- num_scanlines = 32;
- } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
- num_scanlines = 16;
- }
+ } else if (compression_type == TINYEXR_COMPRESSIONTYPE_RLE) {
+ // (buf.size() * 3) / 2 would be enough.
+ std::vector<unsigned char> block((buf.size() * 3) / 2);
- // Write attributes.
- std::vector<tinyexr::ChannelInfo> channels;
- {
- std::vector<unsigned char> data;
+ tinyexr::tinyexr_uint64 outSize = block.size();
- for (int c = 0; c < exr_header->num_channels; c++) {
- tinyexr::ChannelInfo info;
- info.p_linear = 0;
- info.pixel_type = exr_header->requested_pixel_types[c];
- info.x_sampling = 1;
- info.y_sampling = 1;
- info.name = std::string(exr_header->channels[c].name);
- channels.push_back(info);
- }
+ tinyexr::CompressRle(&block.at(0), outSize,
+ reinterpret_cast<const unsigned char *>(&buf.at(0)),
+ static_cast<unsigned long>(buf.size()));
- tinyexr::WriteChannelInfo(data, channels);
+ // 4 byte: scan line
+ // 4 byte: data size
+ // ~ : pixel data(compressed)
+ unsigned int data_len = static_cast<unsigned int>(outSize); // truncate
+ out_data.insert(out_data.end(), block.begin(), block.begin() + data_len);
- tinyexr::WriteAttributeToMemory(&memory, "channels", "chlist", &data.at(0),
- static_cast<int>(data.size()));
- }
+ } else if (compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
+#if TINYEXR_USE_PIZ
+ unsigned int bufLen =
+ 8192 + static_cast<unsigned int>(
+ 2 * static_cast<unsigned int>(
+ buf.size())); // @fixme { compute good bound. }
+ std::vector<unsigned char> block(bufLen);
+ unsigned int outSize = static_cast<unsigned int>(block.size());
+
+ CompressPiz(&block.at(0), &outSize,
+ reinterpret_cast<const unsigned char *>(&buf.at(0)),
+ buf.size(), channels, width, num_lines);
+
+ // 4 byte: scan line
+ // 4 byte: data size
+ // ~ : pixel data(compressed)
+ unsigned int data_len = outSize;
+ out_data.insert(out_data.end(), block.begin(), block.begin() + data_len);
- {
- int comp = exr_header->compression_type;
- tinyexr::swap4(&comp);
- tinyexr::WriteAttributeToMemory(
- &memory, "compression", "compression",
- reinterpret_cast<const unsigned char *>(&comp), 1);
- }
+#else
+ assert(0);
+#endif
+ } else if (compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
+#if TINYEXR_USE_ZFP
+ const ZFPCompressionParam* zfp_compression_param = reinterpret_cast<const ZFPCompressionParam*>(compression_param);
+ std::vector<unsigned char> block;
+ unsigned int outSize;
- {
- int data[4] = {0, 0, exr_image->width - 1, exr_image->height - 1};
- tinyexr::swap4(&data[0]);
- tinyexr::swap4(&data[1]);
- tinyexr::swap4(&data[2]);
- tinyexr::swap4(&data[3]);
- tinyexr::WriteAttributeToMemory(
- &memory, "dataWindow", "box2i",
- reinterpret_cast<const unsigned char *>(data), sizeof(int) * 4);
- tinyexr::WriteAttributeToMemory(
- &memory, "displayWindow", "box2i",
- reinterpret_cast<const unsigned char *>(data), sizeof(int) * 4);
- }
+ tinyexr::CompressZfp(
+ &block, &outSize, reinterpret_cast<const float *>(&buf.at(0)),
+ width, num_lines, static_cast<int>(channels.size()), *zfp_compression_param);
- {
- unsigned char line_order = 0; // @fixme { read line_order from EXRHeader }
- tinyexr::WriteAttributeToMemory(&memory, "lineOrder", "lineOrder",
- &line_order, 1);
- }
+ // 4 byte: scan line
+ // 4 byte: data size
+ // ~ : pixel data(compressed)
+ unsigned int data_len = outSize;
+ out_data.insert(out_data.end(), block.begin(), block.begin() + data_len);
- {
- float aspectRatio = 1.0f;
- tinyexr::swap4(&aspectRatio);
- tinyexr::WriteAttributeToMemory(
- &memory, "pixelAspectRatio", "float",
- reinterpret_cast<const unsigned char *>(&aspectRatio), sizeof(float));
+#else
+ (void)compression_param;
+ assert(0);
+#endif
+ } else {
+ assert(0);
+ return false;
}
- {
- float center[2] = {0.0f, 0.0f};
- tinyexr::swap4(&center[0]);
- tinyexr::swap4(&center[1]);
- tinyexr::WriteAttributeToMemory(
- &memory, "screenWindowCenter", "v2f",
- reinterpret_cast<const unsigned char *>(center), 2 * sizeof(float));
+ return true;
+}
+
+static int EncodeTiledLevel(const EXRImage* level_image, const EXRHeader* exr_header,
+ const std::vector<tinyexr::ChannelInfo>& channels,
+ std::vector<std::vector<unsigned char> >& data_list,
+ size_t start_index, // for data_list
+ int num_x_tiles, int num_y_tiles,
+ const std::vector<size_t>& channel_offset_list,
+ int pixel_data_size,
+ const void* compression_param, // must be set if zfp compression is enabled
+ std::string* err) {
+ int num_tiles = num_x_tiles * num_y_tiles;
+ assert(num_tiles == level_image->num_tiles);
+
+ if ((exr_header->tile_size_x > level_image->width || exr_header->tile_size_y > level_image->height) &&
+ level_image->level_x == 0 && level_image->level_y == 0) {
+ if (err) {
+ (*err) += "Failed to encode tile data.\n";
+ }
+ return TINYEXR_ERROR_INVALID_DATA;
}
- {
- float w = static_cast<float>(exr_image->width);
- tinyexr::swap4(&w);
- tinyexr::WriteAttributeToMemory(&memory, "screenWindowWidth", "float",
- reinterpret_cast<const unsigned char *>(&w),
- sizeof(float));
+
+#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0)
+ std::atomic<bool> invalid_data(false);
+#else
+ bool invalid_data(false);
+#endif
+
+#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0)
+ std::vector<std::thread> workers;
+ std::atomic<int> tile_count(0);
+
+ int num_threads = std::max(1, int(std::thread::hardware_concurrency()));
+ if (num_threads > int(num_tiles)) {
+ num_threads = int(num_tiles);
}
- // Custom attributes
- if (exr_header->num_custom_attributes > 0) {
- for (int i = 0; i < exr_header->num_custom_attributes; i++) {
- tinyexr::WriteAttributeToMemory(
- &memory, exr_header->custom_attributes[i].name,
- exr_header->custom_attributes[i].type,
- reinterpret_cast<const unsigned char *>(
- exr_header->custom_attributes[i].value),
- exr_header->custom_attributes[i].size);
+ for (int t = 0; t < num_threads; t++) {
+ workers.emplace_back(std::thread([&]() {
+ int i = 0;
+ while ((i = tile_count++) < num_tiles) {
+
+#else
+ // Use signed int since some OpenMP compiler doesn't allow unsigned type for
+ // `parallel for`
+#if TINYEXR_USE_OPENMP
+#pragma omp parallel for
+#endif
+ for (int i = 0; i < num_tiles; i++) {
+
+#endif
+ size_t tile_idx = static_cast<size_t>(i);
+ size_t data_idx = tile_idx + start_index;
+
+ int x_tile = i % num_x_tiles;
+ int y_tile = i / num_x_tiles;
+
+ EXRTile& tile = level_image->tiles[tile_idx];
+
+ const unsigned char* const* images =
+ static_cast<const unsigned char* const*>(tile.images);
+
+ data_list[data_idx].resize(5*sizeof(int));
+ size_t data_header_size = data_list[data_idx].size();
+ bool ret = EncodePixelData(data_list[data_idx],
+ images,
+ exr_header->compression_type,
+ 0, // increasing y
+ tile.width,
+ exr_header->tile_size_y,
+ exr_header->tile_size_x,
+ 0,
+ tile.height,
+ pixel_data_size,
+ channels,
+ channel_offset_list,
+ compression_param);
+ if (!ret) {
+ invalid_data = true;
+ continue;
}
+ assert(data_list[data_idx].size() > data_header_size);
+ int data_len = static_cast<int>(data_list[data_idx].size() - data_header_size);
+ //tileX, tileY, levelX, levelY // pixel_data_size(int)
+ memcpy(&data_list[data_idx][0], &x_tile, sizeof(int));
+ memcpy(&data_list[data_idx][4], &y_tile, sizeof(int));
+ memcpy(&data_list[data_idx][8], &level_image->level_x, sizeof(int));
+ memcpy(&data_list[data_idx][12], &level_image->level_y, sizeof(int));
+ memcpy(&data_list[data_idx][16], &data_len, sizeof(int));
+
+ swap4(reinterpret_cast<int*>(&data_list[data_idx][0]));
+ swap4(reinterpret_cast<int*>(&data_list[data_idx][4]));
+ swap4(reinterpret_cast<int*>(&data_list[data_idx][8]));
+ swap4(reinterpret_cast<int*>(&data_list[data_idx][12]));
+ swap4(reinterpret_cast<int*>(&data_list[data_idx][16]));
+
+#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0)
}
+}));
+ }
- { // end of header
- unsigned char e = 0;
- memory.push_back(e);
+ for (auto &t : workers) {
+ t.join();
+ }
+#else
+ } // omp parallel
+#endif
+
+ if (invalid_data) {
+ if (err) {
+ (*err) += "Failed to encode tile data.\n";
+ }
+ return TINYEXR_ERROR_INVALID_DATA;
}
+ return TINYEXR_SUCCESS;
+}
- int num_blocks = exr_image->height / num_scanlines;
- if (num_blocks * num_scanlines < exr_image->height) {
- num_blocks++;
+static int NumScanlines(int compression_type) {
+ int num_scanlines = 1;
+ if (compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) {
+ num_scanlines = 16;
+ } else if (compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
+ num_scanlines = 32;
+ } else if (compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
+ num_scanlines = 16;
}
+ return num_scanlines;
+}
- std::vector<tinyexr::tinyexr_uint64> offsets(static_cast<size_t>(num_blocks));
+static int EncodeChunk(const EXRImage* exr_image, const EXRHeader* exr_header,
+ const std::vector<ChannelInfo>& channels,
+ int num_blocks,
+ tinyexr_uint64 chunk_offset, // starting offset of current chunk
+ bool is_multipart,
+ OffsetData& offset_data, // output block offsets, must be initialized
+ std::vector<std::vector<unsigned char> >& data_list, // output
+ tinyexr_uint64& total_size, // output: ending offset of current chunk
+ std::string* err) {
+ int num_scanlines = NumScanlines(exr_header->compression_type);
- size_t headerSize = memory.size();
- tinyexr::tinyexr_uint64 offset =
- headerSize +
- static_cast<size_t>(num_blocks) *
- sizeof(
- tinyexr::tinyexr_int64); // sizeof(header) + sizeof(offsetTable)
+ data_list.resize(num_blocks);
- std::vector<std::vector<unsigned char> > data_list(
- static_cast<size_t>(num_blocks));
std::vector<size_t> channel_offset_list(
- static_cast<size_t>(exr_header->num_channels));
+ static_cast<size_t>(exr_header->num_channels));
int pixel_data_size = 0;
- size_t channel_offset = 0;
- for (size_t c = 0; c < static_cast<size_t>(exr_header->num_channels); c++) {
- channel_offset_list[c] = channel_offset;
- if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
- pixel_data_size += sizeof(unsigned short);
- channel_offset += sizeof(unsigned short);
- } else if (exr_header->requested_pixel_types[c] ==
- TINYEXR_PIXELTYPE_FLOAT) {
- pixel_data_size += sizeof(float);
- channel_offset += sizeof(float);
- } else if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT) {
- pixel_data_size += sizeof(unsigned int);
- channel_offset += sizeof(unsigned int);
- } else {
- assert(0);
+ {
+ size_t channel_offset = 0;
+ for (size_t c = 0; c < static_cast<size_t>(exr_header->num_channels); c++) {
+ channel_offset_list[c] = channel_offset;
+ if (channels[c].requested_pixel_type == TINYEXR_PIXELTYPE_HALF) {
+ pixel_data_size += sizeof(unsigned short);
+ channel_offset += sizeof(unsigned short);
+ } else if (channels[c].requested_pixel_type ==
+ TINYEXR_PIXELTYPE_FLOAT) {
+ pixel_data_size += sizeof(float);
+ channel_offset += sizeof(float);
+ } else if (channels[c].requested_pixel_type == TINYEXR_PIXELTYPE_UINT) {
+ pixel_data_size += sizeof(unsigned int);
+ channel_offset += sizeof(unsigned int);
+ } else {
+ assert(0);
+ }
}
}
+ const void* compression_param = 0;
#if TINYEXR_USE_ZFP
tinyexr::ZFPCompressionParam zfp_compression_param;
@@ -12364,304 +6754,517 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
{
std::string e;
bool ret = tinyexr::FindZFPCompressionParam(
- &zfp_compression_param, exr_header->custom_attributes,
- exr_header->num_custom_attributes, &e);
+ &zfp_compression_param, exr_header->custom_attributes,
+ exr_header->num_custom_attributes, &e);
if (!ret) {
// Use predefined compression parameter.
zfp_compression_param.type = 0;
zfp_compression_param.rate = 2;
}
+ compression_param = &zfp_compression_param;
}
#endif
- // TODO(LTE): C++11 thread
+ tinyexr_uint64 offset = chunk_offset;
+ tinyexr_uint64 doffset = is_multipart ? 4u : 0u;
-// Use signed int since some OpenMP compiler doesn't allow unsigned type for
-// `parallel for`
-#if TINYEXR_USE_OPENMP
-#pragma omp parallel for
-#endif
- for (int i = 0; i < num_blocks; i++) {
- size_t ii = static_cast<size_t>(i);
- int start_y = num_scanlines * i;
- int endY = (std::min)(num_scanlines * (i + 1), exr_image->height);
- int h = endY - start_y;
-
- std::vector<unsigned char> buf(
- static_cast<size_t>(exr_image->width * h * pixel_data_size));
+ if (exr_image->tiles) {
+ const EXRImage* level_image = exr_image;
+ size_t block_idx = 0;
+ tinyexr::tinyexr_uint64 block_data_size = 0;
+ int num_levels = (exr_header->tile_level_mode != TINYEXR_TILE_RIPMAP_LEVELS) ?
+ offset_data.num_x_levels : (offset_data.num_x_levels * offset_data.num_y_levels);
+ for (int level_index = 0; level_index < num_levels; ++level_index) {
+ if (!level_image) {
+ if (err) {
+ (*err) += "Invalid number of tiled levels for EncodeChunk\n";
+ }
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
- for (size_t c = 0; c < static_cast<size_t>(exr_header->num_channels); c++) {
- if (exr_header->pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
- if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) {
- for (int y = 0; y < h; y++) {
- // Assume increasing Y
- float *line_ptr = reinterpret_cast<float *>(&buf.at(
- static_cast<size_t>(pixel_data_size * y * exr_image->width) +
- channel_offset_list[c] *
- static_cast<size_t>(exr_image->width)));
- for (int x = 0; x < exr_image->width; x++) {
- tinyexr::FP16 h16;
- h16.u = reinterpret_cast<unsigned short **>(
- exr_image->images)[c][(y + start_y) * exr_image->width + x];
-
- tinyexr::FP32 f32 = half_to_float(h16);
-
- tinyexr::swap4(&f32.f);
-
- // line_ptr[x] = f32.f;
- tinyexr::cpy4(line_ptr + x, &(f32.f));
- }
- }
- } else if (exr_header->requested_pixel_types[c] ==
- TINYEXR_PIXELTYPE_HALF) {
- for (int y = 0; y < h; y++) {
- // Assume increasing Y
- unsigned short *line_ptr = reinterpret_cast<unsigned short *>(
- &buf.at(static_cast<size_t>(pixel_data_size * y *
- exr_image->width) +
- channel_offset_list[c] *
- static_cast<size_t>(exr_image->width)));
- for (int x = 0; x < exr_image->width; x++) {
- unsigned short val = reinterpret_cast<unsigned short **>(
- exr_image->images)[c][(y + start_y) * exr_image->width + x];
-
- tinyexr::swap2(&val);
-
- // line_ptr[x] = val;
- tinyexr::cpy2(line_ptr + x, &val);
- }
- }
- } else {
- assert(0);
+ int level_index_from_image = LevelIndex(level_image->level_x, level_image->level_y,
+ exr_header->tile_level_mode, offset_data.num_x_levels);
+ if (level_index_from_image != level_index) {
+ if (err) {
+ (*err) += "Incorrect level ordering in tiled image\n";
}
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
+ int num_y_tiles = (int)offset_data.offsets[level_index].size();
+ assert(num_y_tiles);
+ int num_x_tiles = (int)offset_data.offsets[level_index][0].size();
+ assert(num_x_tiles);
+
+ std::string e;
+ int ret = EncodeTiledLevel(level_image,
+ exr_header,
+ channels,
+ data_list,
+ block_idx,
+ num_x_tiles,
+ num_y_tiles,
+ channel_offset_list,
+ pixel_data_size,
+ compression_param,
+ &e);
+ if (ret != TINYEXR_SUCCESS) {
+ if (!e.empty() && err) {
+ (*err) += e;
+ }
+ return ret;
+ }
- } else if (exr_header->pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) {
- if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
- for (int y = 0; y < h; y++) {
- // Assume increasing Y
- unsigned short *line_ptr = reinterpret_cast<unsigned short *>(
- &buf.at(static_cast<size_t>(pixel_data_size * y *
- exr_image->width) +
- channel_offset_list[c] *
- static_cast<size_t>(exr_image->width)));
- for (int x = 0; x < exr_image->width; x++) {
- tinyexr::FP32 f32;
- f32.f = reinterpret_cast<float **>(
- exr_image->images)[c][(y + start_y) * exr_image->width + x];
-
- tinyexr::FP16 h16;
- h16 = float_to_half_full(f32);
-
- tinyexr::swap2(reinterpret_cast<unsigned short *>(&h16.u));
-
- // line_ptr[x] = h16.u;
- tinyexr::cpy2(line_ptr + x, &(h16.u));
- }
- }
- } else if (exr_header->requested_pixel_types[c] ==
- TINYEXR_PIXELTYPE_FLOAT) {
- for (int y = 0; y < h; y++) {
- // Assume increasing Y
- float *line_ptr = reinterpret_cast<float *>(&buf.at(
- static_cast<size_t>(pixel_data_size * y * exr_image->width) +
- channel_offset_list[c] *
- static_cast<size_t>(exr_image->width)));
- for (int x = 0; x < exr_image->width; x++) {
- float val = reinterpret_cast<float **>(
- exr_image->images)[c][(y + start_y) * exr_image->width + x];
-
- tinyexr::swap4(&val);
-
- // line_ptr[x] = val;
- tinyexr::cpy4(line_ptr + x, &val);
- }
- }
- } else {
- assert(0);
+ for (size_t j = 0; j < static_cast<size_t>(num_y_tiles); ++j)
+ for (size_t i = 0; i < static_cast<size_t>(num_x_tiles); ++i) {
+ offset_data.offsets[level_index][j][i] = offset;
+ swap8(reinterpret_cast<tinyexr_uint64*>(&offset_data.offsets[level_index][j][i]));
+ offset += data_list[block_idx].size() + doffset;
+ block_data_size += data_list[block_idx].size();
+ ++block_idx;
}
- } else if (exr_header->pixel_types[c] == TINYEXR_PIXELTYPE_UINT) {
- for (int y = 0; y < h; y++) {
- // Assume increasing Y
- unsigned int *line_ptr = reinterpret_cast<unsigned int *>(&buf.at(
- static_cast<size_t>(pixel_data_size * y * exr_image->width) +
- channel_offset_list[c] * static_cast<size_t>(exr_image->width)));
- for (int x = 0; x < exr_image->width; x++) {
- unsigned int val = reinterpret_cast<unsigned int **>(
- exr_image->images)[c][(y + start_y) * exr_image->width + x];
+ level_image = level_image->next_level;
+ }
+ assert(static_cast<int>(block_idx) == num_blocks);
+ total_size = offset;
+ } else { // scanlines
+ std::vector<tinyexr::tinyexr_uint64>& offsets = offset_data.offsets[0][0];
- tinyexr::swap4(&val);
+#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0)
+ std::atomic<bool> invalid_data(false);
+ std::vector<std::thread> workers;
+ std::atomic<int> block_count(0);
- // line_ptr[x] = val;
- tinyexr::cpy4(line_ptr + x, &val);
- }
- }
+ int num_threads = std::min(std::max(1, int(std::thread::hardware_concurrency())), num_blocks);
+
+ for (int t = 0; t < num_threads; t++) {
+ workers.emplace_back(std::thread([&]() {
+ int i = 0;
+ while ((i = block_count++) < num_blocks) {
+
+#else
+ bool invalid_data(false);
+#if TINYEXR_USE_OPENMP
+#pragma omp parallel for
+#endif
+ for (int i = 0; i < num_blocks; i++) {
+
+#endif
+ int start_y = num_scanlines * i;
+ int end_Y = (std::min)(num_scanlines * (i + 1), exr_image->height);
+ int num_lines = end_Y - start_y;
+
+ const unsigned char* const* images =
+ static_cast<const unsigned char* const*>(exr_image->images);
+
+ data_list[i].resize(2*sizeof(int));
+ size_t data_header_size = data_list[i].size();
+
+ bool ret = EncodePixelData(data_list[i],
+ images,
+ exr_header->compression_type,
+ 0, // increasing y
+ exr_image->width,
+ exr_image->height,
+ exr_image->width,
+ start_y,
+ num_lines,
+ pixel_data_size,
+ channels,
+ channel_offset_list,
+ compression_param);
+ if (!ret) {
+ invalid_data = true;
+ continue; // "break" cannot be used with OpenMP
}
+ assert(data_list[i].size() > data_header_size);
+ int data_len = static_cast<int>(data_list[i].size() - data_header_size);
+ memcpy(&data_list[i][0], &start_y, sizeof(int));
+ memcpy(&data_list[i][4], &data_len, sizeof(int));
+
+ swap4(reinterpret_cast<int*>(&data_list[i][0]));
+ swap4(reinterpret_cast<int*>(&data_list[i][4]));
+#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0)
+ }
+ }));
}
- if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_NONE) {
- // 4 byte: scan line
- // 4 byte: data size
- // ~ : pixel data(uncompressed)
- std::vector<unsigned char> header(8);
- unsigned int data_len = static_cast<unsigned int>(buf.size());
- memcpy(&header.at(0), &start_y, sizeof(int));
- memcpy(&header.at(4), &data_len, sizeof(unsigned int));
+ for (auto &t : workers) {
+ t.join();
+ }
+#else
+ } // omp parallel
+#endif
+
+ if (invalid_data) {
+ if (err) {
+ (*err) += "Failed to encode scanline data.\n";
+ }
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
- tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(0)));
- tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(4)));
+ for (size_t i = 0; i < static_cast<size_t>(num_blocks); i++) {
+ offsets[i] = offset;
+ tinyexr::swap8(reinterpret_cast<tinyexr::tinyexr_uint64 *>(&offsets[i]));
+ offset += data_list[i].size() + doffset;
+ }
- data_list[ii].insert(data_list[ii].end(), header.begin(), header.end());
- data_list[ii].insert(data_list[ii].end(), buf.begin(),
- buf.begin() + data_len);
+ total_size = static_cast<size_t>(offset);
+ }
+ return TINYEXR_SUCCESS;
+}
- } else if ((exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZIPS) ||
- (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZIP)) {
-#if TINYEXR_USE_MINIZ
- std::vector<unsigned char> block(tinyexr::miniz::mz_compressBound(
- static_cast<unsigned long>(buf.size())));
+// can save a single or multi-part image (no deep* formats)
+static size_t SaveEXRNPartImageToMemory(const EXRImage* exr_images,
+ const EXRHeader** exr_headers,
+ unsigned int num_parts,
+ unsigned char** memory_out, const char** err) {
+ if (exr_images == NULL || exr_headers == NULL || num_parts == 0 ||
+ memory_out == NULL) {
+ SetErrorMessage("Invalid argument for SaveEXRNPartImageToMemory",
+ err);
+ return 0;
+ }
+ {
+ for (unsigned int i = 0; i < num_parts; ++i) {
+ if (exr_headers[i]->compression_type < 0) {
+ SetErrorMessage("Invalid argument for SaveEXRNPartImageToMemory",
+ err);
+ return 0;
+ }
+#if !TINYEXR_USE_PIZ
+ if (exr_headers[i]->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
+ SetErrorMessage("PIZ compression is not supported in this build",
+ err);
+ return 0;
+ }
+#endif
+#if !TINYEXR_USE_ZFP
+ if (exr_headers[i]->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
+ SetErrorMessage("ZFP compression is not supported in this build",
+ err);
+ return 0;
+ }
#else
- std::vector<unsigned char> block(
- compressBound(static_cast<uLong>(buf.size())));
+ for (int c = 0; c < exr_header->num_channels; ++c) {
+ if (exr_headers[i]->requested_pixel_types[c] != TINYEXR_PIXELTYPE_FLOAT) {
+ SetErrorMessage("Pixel type must be FLOAT for ZFP compression",
+ err);
+ return 0;
+ }
+ }
#endif
- tinyexr::tinyexr_uint64 outSize = block.size();
-
- tinyexr::CompressZip(&block.at(0), outSize,
- reinterpret_cast<const unsigned char *>(&buf.at(0)),
- static_cast<unsigned long>(buf.size()));
+ }
+ }
- // 4 byte: scan line
- // 4 byte: data size
- // ~ : pixel data(compressed)
- std::vector<unsigned char> header(8);
- unsigned int data_len = static_cast<unsigned int>(outSize); // truncate
- memcpy(&header.at(0), &start_y, sizeof(int));
- memcpy(&header.at(4), &data_len, sizeof(unsigned int));
+ std::vector<unsigned char> memory;
- tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(0)));
- tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(4)));
+ // Header
+ {
+ const char header[] = { 0x76, 0x2f, 0x31, 0x01 };
+ memory.insert(memory.end(), header, header + 4);
+ }
- data_list[ii].insert(data_list[ii].end(), header.begin(), header.end());
- data_list[ii].insert(data_list[ii].end(), block.begin(),
- block.begin() + data_len);
+ // Version
+ // using value from the first header
+ int long_name = exr_headers[0]->long_name;
+ {
+ char marker[] = { 2, 0, 0, 0 };
+ /* @todo
+ if (exr_header->non_image) {
+ marker[1] |= 0x8;
+ }
+ */
+ // tiled
+ if (num_parts == 1 && exr_images[0].tiles) {
+ marker[1] |= 0x2;
+ }
+ // long_name
+ if (long_name) {
+ marker[1] |= 0x4;
+ }
+ // multipart
+ if (num_parts > 1) {
+ marker[1] |= 0x10;
+ }
+ memory.insert(memory.end(), marker, marker + 4);
+ }
- } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_RLE) {
- // (buf.size() * 3) / 2 would be enough.
- std::vector<unsigned char> block((buf.size() * 3) / 2);
+ int total_chunk_count = 0;
+ std::vector<int> chunk_count(num_parts);
+ std::vector<OffsetData> offset_data(num_parts);
+ for (unsigned int i = 0; i < num_parts; ++i) {
+ if (!exr_images[i].tiles) {
+ int num_scanlines = NumScanlines(exr_headers[i]->compression_type);
+ chunk_count[i] =
+ (exr_images[i].height + num_scanlines - 1) / num_scanlines;
+ InitSingleResolutionOffsets(offset_data[i], chunk_count[i]);
+ total_chunk_count += chunk_count[i];
+ } else {
+ {
+ std::vector<int> num_x_tiles, num_y_tiles;
+ PrecalculateTileInfo(num_x_tiles, num_y_tiles, exr_headers[i]);
+ chunk_count[i] =
+ InitTileOffsets(offset_data[i], exr_headers[i], num_x_tiles, num_y_tiles);
+ total_chunk_count += chunk_count[i];
+ }
+ }
+ }
+ // Write attributes to memory buffer.
+ std::vector< std::vector<tinyexr::ChannelInfo> > channels(num_parts);
+ {
+ std::set<std::string> partnames;
+ for (unsigned int i = 0; i < num_parts; ++i) {
+ //channels
+ {
+ std::vector<unsigned char> data;
+
+ for (int c = 0; c < exr_headers[i]->num_channels; c++) {
+ tinyexr::ChannelInfo info;
+ info.p_linear = 0;
+ info.pixel_type = exr_headers[i]->pixel_types[c];
+ info.requested_pixel_type = exr_headers[i]->requested_pixel_types[c];
+ info.x_sampling = 1;
+ info.y_sampling = 1;
+ info.name = std::string(exr_headers[i]->channels[c].name);
+ channels[i].push_back(info);
+ }
- tinyexr::tinyexr_uint64 outSize = block.size();
+ tinyexr::WriteChannelInfo(data, channels[i]);
- tinyexr::CompressRle(&block.at(0), outSize,
- reinterpret_cast<const unsigned char *>(&buf.at(0)),
- static_cast<unsigned long>(buf.size()));
+ tinyexr::WriteAttributeToMemory(&memory, "channels", "chlist", &data.at(0),
+ static_cast<int>(data.size()));
+ }
- // 4 byte: scan line
- // 4 byte: data size
- // ~ : pixel data(compressed)
- std::vector<unsigned char> header(8);
- unsigned int data_len = static_cast<unsigned int>(outSize); // truncate
- memcpy(&header.at(0), &start_y, sizeof(int));
- memcpy(&header.at(4), &data_len, sizeof(unsigned int));
+ {
+ int comp = exr_headers[i]->compression_type;
+ swap4(&comp);
+ WriteAttributeToMemory(
+ &memory, "compression", "compression",
+ reinterpret_cast<const unsigned char*>(&comp), 1);
+ }
- tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(0)));
- tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(4)));
+ {
+ int data[4] = { 0, 0, exr_images[i].width - 1, exr_images[i].height - 1 };
+ swap4(&data[0]);
+ swap4(&data[1]);
+ swap4(&data[2]);
+ swap4(&data[3]);
+ WriteAttributeToMemory(
+ &memory, "dataWindow", "box2i",
+ reinterpret_cast<const unsigned char*>(data), sizeof(int) * 4);
+
+ int data0[4] = { 0, 0, exr_images[0].width - 1, exr_images[0].height - 1 };
+ swap4(&data0[0]);
+ swap4(&data0[1]);
+ swap4(&data0[2]);
+ swap4(&data0[3]);
+ // Note: must be the same across parts (currently, using value from the first header)
+ WriteAttributeToMemory(
+ &memory, "displayWindow", "box2i",
+ reinterpret_cast<const unsigned char*>(data0), sizeof(int) * 4);
+ }
- data_list[ii].insert(data_list[ii].end(), header.begin(), header.end());
- data_list[ii].insert(data_list[ii].end(), block.begin(),
- block.begin() + data_len);
+ {
+ unsigned char line_order = 0; // @fixme { read line_order from EXRHeader }
+ WriteAttributeToMemory(&memory, "lineOrder", "lineOrder",
+ &line_order, 1);
+ }
- } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
-#if TINYEXR_USE_PIZ
- unsigned int bufLen =
- 8192 + static_cast<unsigned int>(
- 2 * static_cast<unsigned int>(
- buf.size())); // @fixme { compute good bound. }
- std::vector<unsigned char> block(bufLen);
- unsigned int outSize = static_cast<unsigned int>(block.size());
-
- CompressPiz(&block.at(0), &outSize,
- reinterpret_cast<const unsigned char *>(&buf.at(0)),
- buf.size(), channels, exr_image->width, h);
-
- // 4 byte: scan line
- // 4 byte: data size
- // ~ : pixel data(compressed)
- std::vector<unsigned char> header(8);
- unsigned int data_len = outSize;
- memcpy(&header.at(0), &start_y, sizeof(int));
- memcpy(&header.at(4), &data_len, sizeof(unsigned int));
-
- tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(0)));
- tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(4)));
-
- data_list[ii].insert(data_list[ii].end(), header.begin(), header.end());
- data_list[ii].insert(data_list[ii].end(), block.begin(),
- block.begin() + data_len);
+ {
+ // Note: must be the same across parts
+ float aspectRatio = 1.0f;
+ swap4(&aspectRatio);
+ WriteAttributeToMemory(
+ &memory, "pixelAspectRatio", "float",
+ reinterpret_cast<const unsigned char*>(&aspectRatio), sizeof(float));
+ }
-#else
- assert(0);
-#endif
- } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
-#if TINYEXR_USE_ZFP
- std::vector<unsigned char> block;
- unsigned int outSize;
+ {
+ float center[2] = { 0.0f, 0.0f };
+ swap4(&center[0]);
+ swap4(&center[1]);
+ WriteAttributeToMemory(
+ &memory, "screenWindowCenter", "v2f",
+ reinterpret_cast<const unsigned char*>(center), 2 * sizeof(float));
+ }
- tinyexr::CompressZfp(
- &block, &outSize, reinterpret_cast<const float *>(&buf.at(0)),
- exr_image->width, h, exr_header->num_channels, zfp_compression_param);
+ {
+ float w = 1.0f;
+ swap4(&w);
+ WriteAttributeToMemory(&memory, "screenWindowWidth", "float",
+ reinterpret_cast<const unsigned char*>(&w),
+ sizeof(float));
+ }
- // 4 byte: scan line
- // 4 byte: data size
- // ~ : pixel data(compressed)
- std::vector<unsigned char> header(8);
- unsigned int data_len = outSize;
- memcpy(&header.at(0), &start_y, sizeof(int));
- memcpy(&header.at(4), &data_len, sizeof(unsigned int));
+ if (exr_images[i].tiles) {
+ unsigned char tile_mode = static_cast<unsigned char>(exr_headers[i]->tile_level_mode & 0x3);
+ if (exr_headers[i]->tile_rounding_mode) tile_mode |= (1u << 4u);
+ //unsigned char data[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ unsigned int datai[3] = { 0, 0, 0 };
+ unsigned char* data = reinterpret_cast<unsigned char*>(&datai[0]);
+ datai[0] = static_cast<unsigned int>(exr_headers[i]->tile_size_x);
+ datai[1] = static_cast<unsigned int>(exr_headers[i]->tile_size_y);
+ data[8] = tile_mode;
+ swap4(reinterpret_cast<unsigned int*>(&data[0]));
+ swap4(reinterpret_cast<unsigned int*>(&data[4]));
+ WriteAttributeToMemory(
+ &memory, "tiles", "tiledesc",
+ reinterpret_cast<const unsigned char*>(data), 9);
+ }
- tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(0)));
- tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(4)));
+ // must be present for multi-part files - according to spec.
+ if (num_parts > 1) {
+ // name
+ {
+ size_t len = 0;
+ if ((len = strlen(exr_headers[i]->name)) > 0) {
+ partnames.emplace(exr_headers[i]->name);
+ if (partnames.size() != i + 1) {
+ SetErrorMessage("'name' attributes must be unique for a multi-part file", err);
+ return 0;
+ }
+ WriteAttributeToMemory(
+ &memory, "name", "string",
+ reinterpret_cast<const unsigned char*>(exr_headers[i]->name),
+ static_cast<int>(len));
+ } else {
+ SetErrorMessage("Invalid 'name' attribute for a multi-part file", err);
+ return 0;
+ }
+ }
+ // type
+ {
+ const char* type = "scanlineimage";
+ if (exr_images[i].tiles) type = "tiledimage";
+ WriteAttributeToMemory(
+ &memory, "type", "string",
+ reinterpret_cast<const unsigned char*>(type),
+ static_cast<int>(strlen(type)));
+ }
+ // chunkCount
+ {
+ WriteAttributeToMemory(
+ &memory, "chunkCount", "int",
+ reinterpret_cast<const unsigned char*>(&chunk_count[i]),
+ 4);
+ }
+ }
- data_list[ii].insert(data_list[ii].end(), header.begin(), header.end());
- data_list[ii].insert(data_list[ii].end(), block.begin(),
- block.begin() + data_len);
+ // Custom attributes
+ if (exr_headers[i]->num_custom_attributes > 0) {
+ for (int j = 0; j < exr_headers[i]->num_custom_attributes; j++) {
+ tinyexr::WriteAttributeToMemory(
+ &memory, exr_headers[i]->custom_attributes[j].name,
+ exr_headers[i]->custom_attributes[j].type,
+ reinterpret_cast<const unsigned char*>(
+ exr_headers[i]->custom_attributes[j].value),
+ exr_headers[i]->custom_attributes[j].size);
+ }
+ }
-#else
- assert(0);
-#endif
- } else {
- assert(0);
+ { // end of header
+ memory.push_back(0);
+ }
}
- } // omp parallel
-
- for (size_t i = 0; i < static_cast<size_t>(num_blocks); i++) {
- offsets[i] = offset;
- tinyexr::swap8(reinterpret_cast<tinyexr::tinyexr_uint64 *>(&offsets[i]));
- offset += data_list[i].size();
+ }
+ if (num_parts > 1) {
+ // end of header list
+ memory.push_back(0);
}
- size_t totalSize = static_cast<size_t>(offset);
- {
- memory.insert(
- memory.end(), reinterpret_cast<unsigned char *>(&offsets.at(0)),
- reinterpret_cast<unsigned char *>(&offsets.at(0)) +
- sizeof(tinyexr::tinyexr_uint64) * static_cast<size_t>(num_blocks));
+ tinyexr_uint64 chunk_offset = memory.size() + size_t(total_chunk_count) * sizeof(tinyexr_uint64);
+
+ tinyexr_uint64 total_size = 0;
+ std::vector< std::vector< std::vector<unsigned char> > > data_lists(num_parts);
+ for (unsigned int i = 0; i < num_parts; ++i) {
+ std::string e;
+ int ret = EncodeChunk(&exr_images[i], exr_headers[i],
+ channels[i],
+ chunk_count[i],
+ // starting offset of current chunk after part-number
+ chunk_offset,
+ num_parts > 1,
+ offset_data[i], // output: block offsets, must be initialized
+ data_lists[i], // output
+ total_size, // output
+ &e);
+ if (ret != TINYEXR_SUCCESS) {
+ if (!e.empty()) {
+ tinyexr::SetErrorMessage(e, err);
+ }
+ return 0;
+ }
+ chunk_offset = total_size;
}
- if (memory.size() == 0) {
+ // Allocating required memory
+ if (total_size == 0) { // something went wrong
tinyexr::SetErrorMessage("Output memory size is zero", err);
return 0;
}
-
- (*memory_out) = static_cast<unsigned char *>(malloc(totalSize));
- memcpy((*memory_out), &memory.at(0), memory.size());
- unsigned char *memory_ptr = *memory_out + memory.size();
-
- for (size_t i = 0; i < static_cast<size_t>(num_blocks); i++) {
- memcpy(memory_ptr, &data_list[i].at(0), data_list[i].size());
- memory_ptr += data_list[i].size();
+ (*memory_out) = static_cast<unsigned char*>(malloc(total_size));
+
+ // Writing header
+ memcpy((*memory_out), &memory[0], memory.size());
+ unsigned char* memory_ptr = *memory_out + memory.size();
+ size_t sum = memory.size();
+
+ // Writing offset data for chunks
+ for (unsigned int i = 0; i < num_parts; ++i) {
+ if (exr_images[i].tiles) {
+ const EXRImage* level_image = &exr_images[i];
+ int num_levels = (exr_headers[i]->tile_level_mode != TINYEXR_TILE_RIPMAP_LEVELS) ?
+ offset_data[i].num_x_levels : (offset_data[i].num_x_levels * offset_data[i].num_y_levels);
+ for (int level_index = 0; level_index < num_levels; ++level_index) {
+ for (size_t j = 0; j < offset_data[i].offsets[level_index].size(); ++j) {
+ size_t num_bytes = sizeof(tinyexr_uint64) * offset_data[i].offsets[level_index][j].size();
+ sum += num_bytes;
+ assert(sum <= total_size);
+ memcpy(memory_ptr,
+ reinterpret_cast<unsigned char*>(&offset_data[i].offsets[level_index][j][0]),
+ num_bytes);
+ memory_ptr += num_bytes;
+ }
+ level_image = level_image->next_level;
+ }
+ } else {
+ size_t num_bytes = sizeof(tinyexr::tinyexr_uint64) * static_cast<size_t>(chunk_count[i]);
+ sum += num_bytes;
+ assert(sum <= total_size);
+ std::vector<tinyexr::tinyexr_uint64>& offsets = offset_data[i].offsets[0][0];
+ memcpy(memory_ptr, reinterpret_cast<unsigned char*>(&offsets[0]), num_bytes);
+ memory_ptr += num_bytes;
+ }
+ }
+
+ // Writing chunk data
+ for (unsigned int i = 0; i < num_parts; ++i) {
+ for (size_t j = 0; j < static_cast<size_t>(chunk_count[i]); ++j) {
+ if (num_parts > 1) {
+ sum += 4;
+ assert(sum <= total_size);
+ unsigned int part_number = i;
+ swap4(&part_number);
+ memcpy(memory_ptr, &part_number, 4);
+ memory_ptr += 4;
+ }
+ sum += data_lists[i][j].size();
+ assert(sum <= total_size);
+ memcpy(memory_ptr, &data_lists[i][j][0], data_lists[i][j].size());
+ memory_ptr += data_lists[i][j].size();
+ }
}
+ assert(sum == total_size);
+ return total_size; // OK
+}
+
+} // tinyexr
- return totalSize; // OK
+size_t SaveEXRImageToMemory(const EXRImage* exr_image,
+ const EXRHeader* exr_header,
+ unsigned char** memory_out, const char** err) {
+ return tinyexr::SaveEXRNPartImageToMemory(exr_image, &exr_header, 1, memory_out, err);
}
int SaveEXRImageToFile(const EXRImage *exr_image, const EXRHeader *exr_header,
@@ -12690,7 +7293,7 @@ int SaveEXRImageToFile(const EXRImage *exr_image, const EXRHeader *exr_header,
FILE *fp = NULL;
#ifdef _WIN32
-#if defined(_MSC_VER) || defined(__MINGW32__) // MSVC, MinGW gcc or clang
+#if defined(_MSC_VER) || (defined(MINGW_HAS_SECURE_API) && MINGW_HAS_SECURE_API) // MSVC, MinGW GCC, or Clang
errno_t errcode =
_wfopen_s(&fp, tinyexr::UTF8ToWchar(filename).c_str(), L"wb");
if (errcode != 0) {
@@ -12699,7 +7302,7 @@ int SaveEXRImageToFile(const EXRImage *exr_image, const EXRHeader *exr_header,
return TINYEXR_ERROR_CANT_WRITE_FILE;
}
#else
- // Unknown compiler
+ // Unknown compiler or MinGW without MINGW_HAS_SECURE_API.
fp = fopen(filename, "wb");
#endif
#else
@@ -12733,6 +7336,75 @@ int SaveEXRImageToFile(const EXRImage *exr_image, const EXRHeader *exr_header,
return TINYEXR_SUCCESS;
}
+size_t SaveEXRMultipartImageToMemory(const EXRImage* exr_images,
+ const EXRHeader** exr_headers,
+ unsigned int num_parts,
+ unsigned char** memory_out, const char** err) {
+ if (exr_images == NULL || exr_headers == NULL || num_parts < 2 ||
+ memory_out == NULL) {
+ tinyexr::SetErrorMessage("Invalid argument for SaveEXRNPartImageToMemory",
+ err);
+ return 0;
+ }
+ return tinyexr::SaveEXRNPartImageToMemory(exr_images, exr_headers, num_parts, memory_out, err);
+}
+
+int SaveEXRMultipartImageToFile(const EXRImage* exr_images,
+ const EXRHeader** exr_headers,
+ unsigned int num_parts,
+ const char* filename,
+ const char** err) {
+ if (exr_images == NULL || exr_headers == NULL || num_parts < 2) {
+ tinyexr::SetErrorMessage("Invalid argument for SaveEXRMultipartImageToFile",
+ err);
+ return TINYEXR_ERROR_INVALID_ARGUMENT;
+ }
+
+ FILE *fp = NULL;
+#ifdef _WIN32
+#if defined(_MSC_VER) || (defined(MINGW_HAS_SECURE_API) && MINGW_HAS_SECURE_API) // MSVC, MinGW GCC, or Clang.
+ errno_t errcode =
+ _wfopen_s(&fp, tinyexr::UTF8ToWchar(filename).c_str(), L"wb");
+ if (errcode != 0) {
+ tinyexr::SetErrorMessage("Cannot write a file: " + std::string(filename),
+ err);
+ return TINYEXR_ERROR_CANT_WRITE_FILE;
+ }
+#else
+ // Unknown compiler or MinGW without MINGW_HAS_SECURE_API.
+ fp = fopen(filename, "wb");
+#endif
+#else
+ fp = fopen(filename, "wb");
+#endif
+ if (!fp) {
+ tinyexr::SetErrorMessage("Cannot write a file: " + std::string(filename),
+ err);
+ return TINYEXR_ERROR_CANT_WRITE_FILE;
+ }
+
+ unsigned char *mem = NULL;
+ size_t mem_size = SaveEXRMultipartImageToMemory(exr_images, exr_headers, num_parts, &mem, err);
+ if (mem_size == 0) {
+ return TINYEXR_ERROR_SERIALZATION_FAILED;
+ }
+
+ size_t written_size = 0;
+ if ((mem_size > 0) && mem) {
+ written_size = fwrite(mem, 1, mem_size, fp);
+ }
+ free(mem);
+
+ fclose(fp);
+
+ if (written_size != mem_size) {
+ tinyexr::SetErrorMessage("Cannot write a file", err);
+ return TINYEXR_ERROR_CANT_WRITE_FILE;
+ }
+
+ return TINYEXR_SUCCESS;
+}
+
int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
if (deep_image == NULL) {
tinyexr::SetErrorMessage("Invalid argument for LoadDeepEXR", err);
@@ -12741,7 +7413,7 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
#ifdef _WIN32
FILE *fp = NULL;
-#if defined(_MSC_VER) || defined(__MINGW32__) // MSVC, MinGW gcc or clang
+#if defined(_MSC_VER) || (defined(MINGW_HAS_SECURE_API) && MINGW_HAS_SECURE_API) // MSVC, MinGW GCC, or Clang.
errno_t errcode =
_wfopen_s(&fp, tinyexr::UTF8ToWchar(filename).c_str(), L"rb");
if (errcode != 0) {
@@ -12750,7 +7422,7 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
return TINYEXR_ERROR_CANT_OPEN_FILE;
}
#else
- // Unknown compiler
+ // Unknown compiler or MinGW without MINGW_HAS_SECURE_API.
fp = fopen(filename, "rb");
#endif
if (!fp) {
@@ -12917,9 +7589,6 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
int data_width = dw - dx + 1;
int data_height = dh - dy + 1;
- std::vector<float> image(
- static_cast<size_t>(data_width * data_height * 4)); // 4 = RGBA
-
// Read offset tables.
int num_blocks = data_height / num_scanline_blocks;
if (num_blocks * num_scanline_blocks < data_height) {
@@ -13138,6 +7807,9 @@ void InitEXRImage(EXRImage *exr_image) {
exr_image->images = NULL;
exr_image->tiles = NULL;
+ exr_image->next_level = NULL;
+ exr_image->level_x = 0;
+ exr_image->level_y = 0;
exr_image->num_tiles = 0;
}
@@ -13184,14 +7856,43 @@ int FreeEXRHeader(EXRHeader *exr_header) {
free(exr_header->custom_attributes);
}
+ EXRSetNameAttr(exr_header, NULL);
+
return TINYEXR_SUCCESS;
}
+void EXRSetNameAttr(EXRHeader* exr_header, const char* name) {
+ if (exr_header == NULL) {
+ return;
+ }
+ memset(exr_header->name, 0, 256);
+ if (name != NULL) {
+ size_t len = std::min(strlen(name), (size_t)255);
+ if (len) {
+ memcpy(exr_header->name, name, len);
+ }
+ }
+}
+
+int EXRNumLevels(const EXRImage* exr_image) {
+ if (exr_image == NULL) return 0;
+ if(exr_image->images) return 1; // scanlines
+ int levels = 1;
+ const EXRImage* level_image = exr_image;
+ while((level_image = level_image->next_level)) ++levels;
+ return levels;
+}
+
int FreeEXRImage(EXRImage *exr_image) {
if (exr_image == NULL) {
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
+ if (exr_image->next_level) {
+ FreeEXRImage(exr_image->next_level);
+ delete exr_image->next_level;
+ }
+
for (int i = 0; i < exr_image->num_channels; i++) {
if (exr_image->images && exr_image->images[i]) {
free(exr_image->images[i]);
@@ -13229,7 +7930,7 @@ int ParseEXRHeaderFromFile(EXRHeader *exr_header, const EXRVersion *exr_version,
FILE *fp = NULL;
#ifdef _WIN32
-#if defined(_MSC_VER) || defined(__MINGW32__) // MSVC, MinGW gcc or clang
+#if defined(_MSC_VER) || (defined(MINGW_HAS_SECURE_API) && MINGW_HAS_SECURE_API) // MSVC, MinGW GCC, or Clang.
errno_t errcode =
_wfopen_s(&fp, tinyexr::UTF8ToWchar(filename).c_str(), L"rb");
if (errcode != 0) {
@@ -13237,7 +7938,7 @@ int ParseEXRHeaderFromFile(EXRHeader *exr_header, const EXRVersion *exr_version,
return TINYEXR_ERROR_INVALID_FILE;
}
#else
- // Unknown compiler
+ // Unknown compiler or MinGW without MINGW_HAS_SECURE_API.
fp = fopen(filename, "rb");
#endif
#else
@@ -13333,11 +8034,11 @@ int ParseEXRMultipartHeaderFromMemory(EXRHeader ***exr_headers,
static_cast<EXRHeader **>(malloc(sizeof(EXRHeader *) * infos.size()));
for (size_t i = 0; i < infos.size(); i++) {
EXRHeader *exr_header = static_cast<EXRHeader *>(malloc(sizeof(EXRHeader)));
+ memset(exr_header, 0, sizeof(EXRHeader));
ConvertHeader(exr_header, infos[i]);
- // transfoer `tiled` from version.
- exr_header->tiled = exr_version->tiled;
+ exr_header->multipart = exr_version->multipart ? 1 : 0;
(*exr_headers)[i] = exr_header;
}
@@ -13359,7 +8060,7 @@ int ParseEXRMultipartHeaderFromFile(EXRHeader ***exr_headers, int *num_headers,
FILE *fp = NULL;
#ifdef _WIN32
-#if defined(_MSC_VER) || defined(__MINGW32__) // MSVC, MinGW gcc or clang
+#if defined(_MSC_VER) || (defined(MINGW_HAS_SECURE_API) && MINGW_HAS_SECURE_API) // MSVC, MinGW GCC, or Clang.
errno_t errcode =
_wfopen_s(&fp, tinyexr::UTF8ToWchar(filename).c_str(), L"rb");
if (errcode != 0) {
@@ -13367,7 +8068,7 @@ int ParseEXRMultipartHeaderFromFile(EXRHeader ***exr_headers, int *num_headers,
return TINYEXR_ERROR_INVALID_FILE;
}
#else
- // Unknown compiler
+ // Unknown compiler or MinGW without MINGW_HAS_SECURE_API.
fp = fopen(filename, "rb");
#endif
#else
@@ -13465,14 +8166,14 @@ int ParseEXRVersionFromFile(EXRVersion *version, const char *filename) {
FILE *fp = NULL;
#ifdef _WIN32
-#if defined(_MSC_VER) || defined(__MINGW32__) // MSVC, MinGW gcc or clang
+#if defined(_MSC_VER) || (defined(MINGW_HAS_SECURE_API) && MINGW_HAS_SECURE_API) // MSVC, MinGW GCC, or Clang.
errno_t err = _wfopen_s(&fp, tinyexr::UTF8ToWchar(filename).c_str(), L"rb");
if (err != 0) {
// TODO(syoyo): return wfopen_s erro code
return TINYEXR_ERROR_CANT_OPEN_FILE;
}
#else
- // Unknown compiler
+ // Unknown compiler or MinGW without MINGW_HAS_SECURE_API.
fp = fopen(filename, "rb");
#endif
#else
@@ -13543,51 +8244,82 @@ int LoadEXRMultipartImageFromMemory(EXRImage *exr_images,
// http://www.openexr.com/openexrfilelayout.pdf
// Load chunk offset table.
- std::vector<std::vector<tinyexr::tinyexr_uint64> > chunk_offset_table_list;
+ std::vector<tinyexr::OffsetData> chunk_offset_table_list;
+ chunk_offset_table_list.reserve(num_parts);
for (size_t i = 0; i < static_cast<size_t>(num_parts); i++) {
- std::vector<tinyexr::tinyexr_uint64> offset_table(
- static_cast<size_t>(exr_headers[i]->chunk_count));
-
- for (size_t c = 0; c < offset_table.size(); c++) {
- tinyexr::tinyexr_uint64 offset;
- memcpy(&offset, marker, 8);
- tinyexr::swap8(&offset);
+ chunk_offset_table_list.resize(chunk_offset_table_list.size() + 1);
+ tinyexr::OffsetData& offset_data = chunk_offset_table_list.back();
+ if (!exr_headers[i]->tiled || exr_headers[i]->tile_level_mode == TINYEXR_TILE_ONE_LEVEL) {
+ tinyexr::InitSingleResolutionOffsets(offset_data, exr_headers[i]->chunk_count);
+ std::vector<tinyexr::tinyexr_uint64>& offset_table = offset_data.offsets[0][0];
+
+ for (size_t c = 0; c < offset_table.size(); c++) {
+ tinyexr::tinyexr_uint64 offset;
+ memcpy(&offset, marker, 8);
+ tinyexr::swap8(&offset);
+
+ if (offset >= size) {
+ tinyexr::SetErrorMessage("Invalid offset size in EXR header chunks.",
+ err);
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
- if (offset >= size) {
- tinyexr::SetErrorMessage("Invalid offset size in EXR header chunks.",
- err);
- return TINYEXR_ERROR_INVALID_DATA;
+ offset_table[c] = offset + 4; // +4 to skip 'part number'
+ marker += 8;
+ }
+ } else {
+ {
+ std::vector<int> num_x_tiles, num_y_tiles;
+ tinyexr::PrecalculateTileInfo(num_x_tiles, num_y_tiles, exr_headers[i]);
+ int num_blocks = InitTileOffsets(offset_data, exr_headers[i], num_x_tiles, num_y_tiles);
+ if (num_blocks != exr_headers[i]->chunk_count) {
+ tinyexr::SetErrorMessage("Invalid offset table size.", err);
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
+ }
+ for (unsigned int l = 0; l < offset_data.offsets.size(); ++l) {
+ for (unsigned int dy = 0; dy < offset_data.offsets[l].size(); ++dy) {
+ for (unsigned int dx = 0; dx < offset_data.offsets[l][dy].size(); ++dx) {
+ tinyexr::tinyexr_uint64 offset;
+ memcpy(&offset, marker, sizeof(tinyexr::tinyexr_uint64));
+ tinyexr::swap8(&offset);
+ if (offset >= size) {
+ tinyexr::SetErrorMessage("Invalid offset size in EXR header chunks.",
+ err);
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
+ offset_data.offsets[l][dy][dx] = offset + 4; // +4 to skip 'part number'
+ marker += sizeof(tinyexr::tinyexr_uint64); // = 8
+ }
+ }
}
-
- offset_table[c] = offset + 4; // +4 to skip 'part number'
- marker += 8;
}
-
- chunk_offset_table_list.push_back(offset_table);
}
// Decode image.
for (size_t i = 0; i < static_cast<size_t>(num_parts); i++) {
- std::vector<tinyexr::tinyexr_uint64> &offset_table =
- chunk_offset_table_list[i];
+ tinyexr::OffsetData &offset_data = chunk_offset_table_list[i];
// First check 'part number' is identitical to 'i'
- for (size_t c = 0; c < offset_table.size(); c++) {
- const unsigned char *part_number_addr =
- memory + offset_table[c] - 4; // -4 to move to 'part number' field.
- unsigned int part_no;
- memcpy(&part_no, part_number_addr, sizeof(unsigned int)); // 4
- tinyexr::swap4(&part_no);
-
- if (part_no != i) {
- tinyexr::SetErrorMessage("Invalid `part number' in EXR header chunks.",
- err);
- return TINYEXR_ERROR_INVALID_DATA;
- }
- }
+ for (unsigned int l = 0; l < offset_data.offsets.size(); ++l)
+ for (unsigned int dy = 0; dy < offset_data.offsets[l].size(); ++dy)
+ for (unsigned int dx = 0; dx < offset_data.offsets[l][dy].size(); ++dx) {
+
+ const unsigned char *part_number_addr =
+ memory + offset_data.offsets[l][dy][dx] - 4; // -4 to move to 'part number' field.
+ unsigned int part_no;
+ memcpy(&part_no, part_number_addr, sizeof(unsigned int)); // 4
+ tinyexr::swap4(&part_no);
+
+ if (part_no != i) {
+ tinyexr::SetErrorMessage("Invalid `part number' in EXR header chunks.",
+ err);
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
+ }
std::string e;
- int ret = tinyexr::DecodeChunk(&exr_images[i], exr_headers[i], offset_table,
+ int ret = tinyexr::DecodeChunk(&exr_images[i], exr_headers[i], offset_data,
memory, size, &e);
if (ret != TINYEXR_SUCCESS) {
if (!e.empty()) {
@@ -13612,7 +8344,7 @@ int LoadEXRMultipartImageFromFile(EXRImage *exr_images,
FILE *fp = NULL;
#ifdef _WIN32
-#if defined(_MSC_VER) || defined(__MINGW32__) // MSVC, MinGW gcc or clang
+#if defined(_MSC_VER) || (defined(MINGW_HAS_SECURE_API) && MINGW_HAS_SECURE_API) // MSVC, MinGW GCC, or Clang.
errno_t errcode =
_wfopen_s(&fp, tinyexr::UTF8ToWchar(filename).c_str(), L"rb");
if (errcode != 0) {
@@ -13620,7 +8352,7 @@ int LoadEXRMultipartImageFromFile(EXRImage *exr_images,
return TINYEXR_ERROR_CANT_OPEN_FILE;
}
#else
- // Unknown compiler
+ // Unknown compiler or MinGW without MINGW_HAS_SECURE_API.
fp = fopen(filename, "rb");
#endif
#else
diff --git a/thirdparty/wslay/includes/config.h b/thirdparty/wslay/config.h
index 771ad12528..f291801ba1 100644
--- a/thirdparty/wslay/includes/config.h
+++ b/thirdparty/wslay/config.h
@@ -1,8 +1,10 @@
#ifndef CONFIG_H
#define CONFIG_H
+// -- GODOT start --
#ifdef BIG_ENDIAN_ENABLED
#define WORDS_BIGENDIAN
#endif
+// -- GODOT end --
#endif /* CONFIG_H */
diff --git a/thirdparty/wslay/msvcfix.diff b/thirdparty/wslay/patches/msvcfix.diff
index 28721844f4..f58b6d44f0 100644
--- a/thirdparty/wslay/msvcfix.diff
+++ b/thirdparty/wslay/patches/msvcfix.diff
@@ -1,8 +1,8 @@
diff --git a/thirdparty/wslay/includes/wslay/wslay.h b/thirdparty/wslay/includes/wslay/wslay.h
-index 2fde81a4e..9c751b05b 100644
+index 77a4e8253f..ac6873613f 100644
--- a/thirdparty/wslay/includes/wslay/wslay.h
+++ b/thirdparty/wslay/includes/wslay/wslay.h
-@@ -33,6 +33,12 @@ extern "C" {
+@@ -33,6 +33,13 @@ extern "C" {
#include <stdlib.h>
#include <sys/types.h>
@@ -12,6 +12,7 @@ index 2fde81a4e..9c751b05b 100644
+typedef SSIZE_T ssize_t;
+#endif
+/* GODOT END */
-
++
/*
* wslay/wslayver.h is generated from wslay/wslayver.h.in by
+ * configure. The projects which do not use autotools can set
diff --git a/thirdparty/wslay/includes/wslay/wslay.h b/thirdparty/wslay/wslay/wslay.h
index 9c751b05b7..ac6873613f 100644
--- a/thirdparty/wslay/includes/wslay/wslay.h
+++ b/thirdparty/wslay/wslay/wslay.h
@@ -25,7 +25,7 @@
#ifndef WSLAY_H
#define WSLAY_H
-#ifdef __cplusplus
+#ifdef __cplusplus
extern "C" {
#endif
@@ -155,10 +155,10 @@ enum wslay_opcode {
* These macros assume that rsv is constructed by ((RSV1 << 2) |
* (RSV2 << 1) | RSV3)
*/
-#define WSLAY_RSV_NONE ((uint8_t) 0)
-#define WSLAY_RSV1_BIT (((uint8_t) 1) << 2)
-#define WSLAY_RSV2_BIT (((uint8_t) 1) << 1)
-#define WSLAY_RSV3_BIT (((uint8_t) 1) << 0)
+#define WSLAY_RSV_NONE ((uint8_t)0)
+#define WSLAY_RSV1_BIT (((uint8_t)1) << 2)
+#define WSLAY_RSV2_BIT (((uint8_t)1) << 1)
+#define WSLAY_RSV3_BIT (((uint8_t)1) << 0)
#define wslay_get_rsv1(rsv) ((rsv >> 2) & 1)
#define wslay_get_rsv2(rsv) ((rsv >> 1) & 1)
@@ -172,7 +172,7 @@ struct wslay_frame_iocb {
* RFC6455 requires 0 unless extensions are negotiated.
*/
uint8_t rsv;
- /* 4 bit opcode */
+ /* 4 bit opcode */
uint8_t opcode;
/* payload length [0, 2**63-1] */
uint64_t payload_length;
@@ -229,6 +229,33 @@ ssize_t wslay_frame_send(wslay_frame_context_ptr ctx,
struct wslay_frame_iocb *iocb);
/*
+ * Write WebSocket frame specified in iocb to buf of length
+ * buflen. ctx must be initialized using wslay_frame_context_init()
+ * function. iocb->fin must be 1 if this is a fin frame, otherwise 0.
+ * iocb->rsv is reserved bits. iocb->opcode must be the opcode of
+ * this frame. iocb->mask must be 1 if this is masked frame,
+ * otherwise 0. iocb->payload_length is the payload_length of this
+ * frame. iocb->data must point to the payload data to be
+ * sent. iocb->data_length must be the length of the data. Unlike
+ * wslay_frame_send, this function does not call send_callback
+ * function. This function calls gen_mask_callback function if it
+ * needs new mask key. This function returns the number of bytes
+ * written to a buffer. Unlike wslay_frame_send, it includes the
+ * number of header bytes. Instead, the number of payload bytes
+ * written is assigned to *pwpayloadlen if this function succeeds. If
+ * there is not enough space left in a buffer, it returns 0. If the
+ * library detects error in iocb, this function returns
+ * WSLAY_ERR_INVALID_ARGUMENT. If callback functions report a
+ * failure, this function returns WSLAY_ERR_INVALID_CALLBACK. This
+ * function does not always send all given data in iocb. If there are
+ * remaining data to be sent, adjust data and data_length in iocb
+ * accordingly and call this function again.
+ */
+ssize_t wslay_frame_write(wslay_frame_context_ptr ctx,
+ struct wslay_frame_iocb *iocb, uint8_t *buf,
+ size_t buflen, size_t *pwpayloadlen);
+
+/*
* Receives WebSocket frame and stores it in iocb. This function
* returns the number of payload bytes received. This does not
* include header bytes. In this case, iocb will be populated as
@@ -276,9 +303,9 @@ struct wslay_event_on_msg_recv_arg {
* Callback function invoked by wslay_event_recv() when a message is
* completely received.
*/
-typedef void (*wslay_event_on_msg_recv_callback)
-(wslay_event_context_ptr ctx,
- const struct wslay_event_on_msg_recv_arg *arg, void *user_data);
+typedef void (*wslay_event_on_msg_recv_callback)(
+ wslay_event_context_ptr ctx, const struct wslay_event_on_msg_recv_arg *arg,
+ void *user_data);
struct wslay_event_on_frame_recv_start_arg {
/* fin bit; 1 for final frame, or 0. */
@@ -296,9 +323,9 @@ struct wslay_event_on_frame_recv_start_arg {
* starts to be received. This callback function is only invoked once
* for each frame.
*/
-typedef void (*wslay_event_on_frame_recv_start_callback)
-(wslay_event_context_ptr ctx,
- const struct wslay_event_on_frame_recv_start_arg *arg, void *user_data);
+typedef void (*wslay_event_on_frame_recv_start_callback)(
+ wslay_event_context_ptr ctx,
+ const struct wslay_event_on_frame_recv_start_arg *arg, void *user_data);
struct wslay_event_on_frame_recv_chunk_arg {
/* chunk of payload data */
@@ -311,16 +338,16 @@ struct wslay_event_on_frame_recv_chunk_arg {
* Callback function invoked by wslay_event_recv() when a chunk of
* frame payload is received.
*/
-typedef void (*wslay_event_on_frame_recv_chunk_callback)
-(wslay_event_context_ptr ctx,
- const struct wslay_event_on_frame_recv_chunk_arg *arg, void *user_data);
+typedef void (*wslay_event_on_frame_recv_chunk_callback)(
+ wslay_event_context_ptr ctx,
+ const struct wslay_event_on_frame_recv_chunk_arg *arg, void *user_data);
/*
* Callback function invoked by wslay_event_recv() when a frame is
* completely received.
*/
-typedef void (*wslay_event_on_frame_recv_end_callback)
-(wslay_event_context_ptr ctx, void *user_data);
+typedef void (*wslay_event_on_frame_recv_end_callback)(
+ wslay_event_context_ptr ctx, void *user_data);
/*
* Callback function invoked by wslay_event_recv() when it wants to
@@ -394,9 +421,9 @@ struct wslay_event_callbacks {
* WSLAY_ERR_NOMEM
* Out of memory.
*/
-int wslay_event_context_server_init
-(wslay_event_context_ptr *ctx,
- const struct wslay_event_callbacks *callbacks, void *user_data);
+int wslay_event_context_server_init(
+ wslay_event_context_ptr *ctx, const struct wslay_event_callbacks *callbacks,
+ void *user_data);
/*
* Initializes ctx as WebSocket client. user_data is an arbitrary
@@ -409,9 +436,9 @@ int wslay_event_context_server_init
* WSLAY_ERR_NOMEM
* Out of memory.
*/
-int wslay_event_context_client_init
-(wslay_event_context_ptr *ctx,
- const struct wslay_event_callbacks *callbacks, void *user_data);
+int wslay_event_context_client_init(
+ wslay_event_context_ptr *ctx, const struct wslay_event_callbacks *callbacks,
+ void *user_data);
/*
* Releases allocated resources for ctx.
@@ -462,8 +489,8 @@ void wslay_event_config_set_max_recv_msg_length(wslay_event_context_ptr ctx,
* or wslay_event_context_server_init() or
* wslay_event_context_client_init() are replaced with callbacks.
*/
-void wslay_event_config_set_callbacks
-(wslay_event_context_ptr ctx, const struct wslay_event_callbacks *callbacks);
+void wslay_event_config_set_callbacks(
+ wslay_event_context_ptr ctx, const struct wslay_event_callbacks *callbacks);
/*
* Receives messages from peer. When receiving
@@ -538,6 +565,50 @@ int wslay_event_recv(wslay_event_context_ptr ctx);
*/
int wslay_event_send(wslay_event_context_ptr ctx);
+/*
+ * Writes queued messages to a buffer. Unlike wslay_event_send(), this
+ * function writes messages into the given buffer. It does not use
+ * wslay_event_send_callback function. Single call of
+ * wslay_event_write() writes multiple messages until there is not
+ * enough space left in a buffer.
+ *
+ * If ctx is initialized for WebSocket client use, wslay_event_write()
+ * uses wslay_event_genmask_callback to get new mask key.
+ *
+ * buf is a pointer to buffer and its capacity is given in buflen. It
+ * should have at least 14 bytes.
+ *
+ * When a message queued using wslay_event_queue_fragmented_msg() is
+ * sent, wslay_event_write() invokes
+ * wslay_event_fragmented_msg_callback for that message.
+ *
+ * After close control frame is sent, this function calls
+ * wslay_event_set_write_enabled() with second argument 0 to disable
+ * further transmission to peer.
+ *
+ * If there are any pending messages, wslay_event_want_write() returns
+ * 1, otherwise returns 0.
+ *
+ * In case of a fatal errror which leads to negative return code, this
+ * function calls wslay_event_set_write_enabled() with second argument
+ * 0 to disable further transmission to peer.
+ *
+ * wslay_event_write() returns the number of bytes written to a buffer
+ * if it succeeds, or one of the following negative error codes:
+ *
+ * WSLAY_ERR_CALLBACK_FAILURE
+ * User defined callback function is failed.
+ *
+ * WSLAY_ERR_NOMEM
+ * Out of memory.
+ *
+ * When negative error code is returned, application must not make any
+ * further call of wslay_event_write() and must close WebSocket
+ * connection.
+ */
+ssize_t wslay_event_write(wslay_event_context_ptr ctx, uint8_t *buf,
+ size_t buflen);
+
struct wslay_event_msg {
uint8_t opcode;
const uint8_t *msg;
@@ -594,10 +665,9 @@ union wslay_event_msg_source {
* moment, return 0. If there is an error, return -1 and set error
* code WSLAY_ERR_CALLBACK_FAILURE using wslay_event_set_error().
*/
-typedef ssize_t (*wslay_event_fragmented_msg_callback)
-(wslay_event_context_ptr ctx,
- uint8_t *buf, size_t len, const union wslay_event_msg_source *source,
- int *eof, void *user_data);
+typedef ssize_t (*wslay_event_fragmented_msg_callback)(
+ wslay_event_context_ptr ctx, uint8_t *buf, size_t len,
+ const union wslay_event_msg_source *source, int *eof, void *user_data);
struct wslay_event_fragmented_msg {
/* opcode */
@@ -631,15 +701,16 @@ struct wslay_event_fragmented_msg {
* WSLAY_ERR_NOMEM
* Out of memory.
*/
-int wslay_event_queue_fragmented_msg
-(wslay_event_context_ptr ctx, const struct wslay_event_fragmented_msg *arg);
+int wslay_event_queue_fragmented_msg(
+ wslay_event_context_ptr ctx, const struct wslay_event_fragmented_msg *arg);
/*
* Extended version of wslay_event_queue_fragmented_msg which allows to set
* reserved bits.
*/
-int wslay_event_queue_fragmented_msg_ex(wslay_event_context_ptr ctx,
- const struct wslay_event_fragmented_msg *arg, uint8_t rsv);
+int wslay_event_queue_fragmented_msg_ex(
+ wslay_event_context_ptr ctx, const struct wslay_event_fragmented_msg *arg,
+ uint8_t rsv);
/*
* Queues close control frame. This function is provided just for
@@ -669,8 +740,7 @@ int wslay_event_queue_fragmented_msg_ex(wslay_event_context_ptr ctx,
* WSLAY_ERR_NOMEM
* Out of memory.
*/
-int wslay_event_queue_close(wslay_event_context_ptr ctx,
- uint16_t status_code,
+int wslay_event_queue_close(wslay_event_context_ptr ctx, uint16_t status_code,
const uint8_t *reason, size_t reason_length);
/*
diff --git a/thirdparty/wslay/includes/wslay/wslayver.h b/thirdparty/wslay/wslay/wslayver.h
index 28f2018039..28f2018039 100644
--- a/thirdparty/wslay/includes/wslay/wslayver.h
+++ b/thirdparty/wslay/wslay/wslayver.h
diff --git a/thirdparty/wslay/wslay_event.c b/thirdparty/wslay/wslay_event.c
index 140f7c01da..4c29fe4000 100644
--- a/thirdparty/wslay/wslay_event.c
+++ b/thirdparty/wslay/wslay_event.c
@@ -28,9 +28,9 @@
#include <assert.h>
#include <stdio.h>
-#include "wslay_queue.h"
#include "wslay_frame.h"
#include "wslay_net.h"
+#include "wslay_macro.h"
/* Start of utf8 dfa */
/* Copyright (c) 2008-2010 Bjoern Hoehrmann <bjoern@hoehrmann.de>
* See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
@@ -60,6 +60,7 @@
#define UTF8_ACCEPT 0
#define UTF8_REJECT 12
+/* clang-format off */
static const uint8_t utf8d[] = {
/*
* The first part of the table maps bytes to character classes that
@@ -84,14 +85,13 @@ static const uint8_t utf8d[] = {
12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
12,36,12,12,12,12,12,12,12,12,12,12,
};
+/* clang-format on */
-static uint32_t
-decode(uint32_t* state, uint32_t* codep, uint32_t byte) {
+static uint32_t decode(uint32_t *state, uint32_t *codep, uint32_t byte) {
uint32_t type = utf8d[byte];
- *codep = (*state != UTF8_ACCEPT) ?
- (byte & 0x3fu) | (*codep << 6) :
- (0xff >> type) & (byte);
+ *codep = (*state != UTF8_ACCEPT) ? (byte & 0x3fu) | (*codep << 6)
+ : (0xff >> type) & (byte);
*state = utf8d[256 + *state + type];
return *state;
@@ -100,117 +100,96 @@ decode(uint32_t* state, uint32_t* codep, uint32_t byte) {
/* End of utf8 dfa */
static ssize_t wslay_event_frame_recv_callback(uint8_t *buf, size_t len,
- int flags, void *user_data)
-{
+ int flags, void *user_data) {
struct wslay_event_frame_user_data *e =
- (struct wslay_event_frame_user_data*)user_data;
+ (struct wslay_event_frame_user_data *)user_data;
return e->ctx->callbacks.recv_callback(e->ctx, buf, len, flags, e->user_data);
}
static ssize_t wslay_event_frame_send_callback(const uint8_t *data, size_t len,
- int flags, void *user_data)
-{
+ int flags, void *user_data) {
struct wslay_event_frame_user_data *e =
- (struct wslay_event_frame_user_data*)user_data;
+ (struct wslay_event_frame_user_data *)user_data;
return e->ctx->callbacks.send_callback(e->ctx, data, len, flags,
e->user_data);
}
static int wslay_event_frame_genmask_callback(uint8_t *buf, size_t len,
- void *user_data)
-{
+ void *user_data) {
struct wslay_event_frame_user_data *e =
- (struct wslay_event_frame_user_data*)user_data;
+ (struct wslay_event_frame_user_data *)user_data;
return e->ctx->callbacks.genmask_callback(e->ctx, buf, len, e->user_data);
}
-static int wslay_event_byte_chunk_init
-(struct wslay_event_byte_chunk **chunk, size_t len)
-{
- *chunk = (struct wslay_event_byte_chunk*)malloc
- (sizeof(struct wslay_event_byte_chunk));
- if(*chunk == NULL) {
+static int wslay_event_byte_chunk_init(struct wslay_event_byte_chunk **chunk,
+ size_t len) {
+ *chunk = malloc(sizeof(struct wslay_event_byte_chunk) + len);
+ if (*chunk == NULL) {
return WSLAY_ERR_NOMEM;
}
memset(*chunk, 0, sizeof(struct wslay_event_byte_chunk));
- if(len) {
- (*chunk)->data = (uint8_t*)malloc(len);
- if((*chunk)->data == NULL) {
- free(*chunk);
- return WSLAY_ERR_NOMEM;
- }
+ if (len) {
+ (*chunk)->data = (uint8_t *)(*chunk) + sizeof(**chunk);
(*chunk)->data_length = len;
}
return 0;
}
-static void wslay_event_byte_chunk_free(struct wslay_event_byte_chunk *c)
-{
- if(!c) {
- return;
- }
- free(c->data);
+static void wslay_event_byte_chunk_free(struct wslay_event_byte_chunk *c) {
free(c);
}
static void wslay_event_byte_chunk_copy(struct wslay_event_byte_chunk *c,
- size_t off,
- const uint8_t *data, size_t data_length)
-{
- memcpy(c->data+off, data, data_length);
+ size_t off, const uint8_t *data,
+ size_t data_length) {
+ memcpy(c->data + off, data, data_length);
}
-static void wslay_event_imsg_set(struct wslay_event_imsg *m,
- uint8_t fin, uint8_t rsv, uint8_t opcode)
-{
+static void wslay_event_imsg_set(struct wslay_event_imsg *m, uint8_t fin,
+ uint8_t rsv, uint8_t opcode) {
m->fin = fin;
m->rsv = rsv;
m->opcode = opcode;
m->msg_length = 0;
}
-static void wslay_event_imsg_chunks_free(struct wslay_event_imsg *m)
-{
- if(!m->chunks) {
- return;
- }
- while(!wslay_queue_empty(m->chunks)) {
- wslay_event_byte_chunk_free(wslay_queue_top(m->chunks));
- wslay_queue_pop(m->chunks);
+static void wslay_event_imsg_chunks_free(struct wslay_event_imsg *m) {
+ while (!wslay_queue_empty(&m->chunks)) {
+ struct wslay_event_byte_chunk *chunk = wslay_struct_of(
+ wslay_queue_top(&m->chunks), struct wslay_event_byte_chunk, qe);
+ wslay_queue_pop(&m->chunks);
+ wslay_event_byte_chunk_free(chunk);
}
}
-static void wslay_event_imsg_reset(struct wslay_event_imsg *m)
-{
+static void wslay_event_imsg_reset(struct wslay_event_imsg *m) {
m->opcode = 0xffu;
m->utf8state = UTF8_ACCEPT;
wslay_event_imsg_chunks_free(m);
}
-static int wslay_event_imsg_append_chunk(struct wslay_event_imsg *m, size_t len)
-{
- if(len == 0) {
+static int wslay_event_imsg_append_chunk(struct wslay_event_imsg *m,
+ size_t len) {
+ if (len == 0) {
return 0;
} else {
int r;
struct wslay_event_byte_chunk *chunk;
- if((r = wslay_event_byte_chunk_init(&chunk, len)) != 0) {
- return r;
- }
- if((r = wslay_queue_push(m->chunks, chunk)) != 0) {
+ if ((r = wslay_event_byte_chunk_init(&chunk, len)) != 0) {
return r;
}
+ wslay_queue_push(&m->chunks, &chunk->qe);
m->msg_length += len;
return 0;
}
}
-static int wslay_event_omsg_non_fragmented_init
-(struct wslay_event_omsg **m, uint8_t opcode, uint8_t rsv,
- const uint8_t *msg, size_t msg_length)
-{
- *m = (struct wslay_event_omsg*)malloc(sizeof(struct wslay_event_omsg));
- if(!*m) {
+static int wslay_event_omsg_non_fragmented_init(struct wslay_event_omsg **m,
+ uint8_t opcode, uint8_t rsv,
+ const uint8_t *msg,
+ size_t msg_length) {
+ *m = malloc(sizeof(struct wslay_event_omsg) + msg_length);
+ if (!*m) {
return WSLAY_ERR_NOMEM;
}
memset(*m, 0, sizeof(struct wslay_event_omsg));
@@ -218,28 +197,22 @@ static int wslay_event_omsg_non_fragmented_init
(*m)->opcode = opcode;
(*m)->rsv = rsv;
(*m)->type = WSLAY_NON_FRAGMENTED;
- if(msg_length) {
- (*m)->data = (uint8_t*)malloc(msg_length);
- if(!(*m)->data) {
- free(*m);
- return WSLAY_ERR_NOMEM;
- }
+ if (msg_length) {
+ (*m)->data = (uint8_t *)(*m) + sizeof(**m);
memcpy((*m)->data, msg, msg_length);
(*m)->data_length = msg_length;
}
return 0;
}
-static int wslay_event_omsg_fragmented_init
-(struct wslay_event_omsg **m, uint8_t opcode, uint8_t rsv,
- const union wslay_event_msg_source source,
- wslay_event_fragmented_msg_callback read_callback)
-{
- *m = (struct wslay_event_omsg*)malloc(sizeof(struct wslay_event_omsg));
- if(!*m) {
+static int wslay_event_omsg_fragmented_init(
+ struct wslay_event_omsg **m, uint8_t opcode, uint8_t rsv,
+ const union wslay_event_msg_source source,
+ wslay_event_fragmented_msg_callback read_callback) {
+ *m = calloc(1, sizeof(struct wslay_event_omsg));
+ if (!*m) {
return WSLAY_ERR_NOMEM;
}
- memset(*m, 0, sizeof(struct wslay_event_omsg));
(*m)->opcode = opcode;
(*m)->rsv = rsv;
(*m)->type = WSLAY_FRAGMENTED;
@@ -248,31 +221,25 @@ static int wslay_event_omsg_fragmented_init
return 0;
}
-static void wslay_event_omsg_free(struct wslay_event_omsg *m)
-{
- if(!m) {
- return;
- }
- free(m->data);
- free(m);
-}
+static void wslay_event_omsg_free(struct wslay_event_omsg *m) { free(m); }
-static uint8_t* wslay_event_flatten_queue(struct wslay_queue *queue, size_t len)
-{
- if(len == 0) {
+static uint8_t *wslay_event_flatten_queue(struct wslay_queue *queue,
+ size_t len) {
+ if (len == 0) {
return NULL;
} else {
size_t off = 0;
- uint8_t *buf = (uint8_t*)malloc(len);
- if(!buf) {
+ uint8_t *buf = malloc(len);
+ if (!buf) {
return NULL;
}
- while(!wslay_queue_empty(queue)) {
- struct wslay_event_byte_chunk *chunk = wslay_queue_top(queue);
- memcpy(buf+off, chunk->data, chunk->data_length);
+ while (!wslay_queue_empty(queue)) {
+ struct wslay_event_byte_chunk *chunk = wslay_struct_of(
+ wslay_queue_top(queue), struct wslay_event_byte_chunk, qe);
+ wslay_queue_pop(queue);
+ memcpy(buf + off, chunk->data, chunk->data_length);
off += chunk->data_length;
wslay_event_byte_chunk_free(chunk);
- wslay_queue_pop(queue);
assert(off <= len);
}
assert(len == off);
@@ -280,17 +247,15 @@ static uint8_t* wslay_event_flatten_queue(struct wslay_queue *queue, size_t len)
}
}
-static int wslay_event_is_msg_queueable(wslay_event_context_ptr ctx)
-{
+static int wslay_event_is_msg_queueable(wslay_event_context_ptr ctx) {
return ctx->write_enabled && (ctx->close_status & WSLAY_CLOSE_QUEUED) == 0;
}
int wslay_event_queue_close(wslay_event_context_ptr ctx, uint16_t status_code,
- const uint8_t *reason, size_t reason_length)
-{
- if(!wslay_event_is_msg_queueable(ctx)) {
+ const uint8_t *reason, size_t reason_length) {
+ if (!wslay_event_is_msg_queueable(ctx)) {
return WSLAY_ERR_NO_MORE_MSG;
- } else if(reason_length > 123) {
+ } else if (reason_length > 123) {
return WSLAY_ERR_INVALID_ARGUMENT;
} else {
uint8_t msg[128];
@@ -298,231 +263,203 @@ int wslay_event_queue_close(wslay_event_context_ptr ctx, uint16_t status_code,
struct wslay_event_msg arg;
uint16_t ncode;
int r;
- if(status_code == 0) {
+ if (status_code == 0) {
msg_length = 0;
} else {
ncode = htons(status_code);
memcpy(msg, &ncode, 2);
- if(reason_length) {
- memcpy(msg+2, reason, reason_length);
+ if (reason_length) {
+ memcpy(msg + 2, reason, reason_length);
}
- msg_length = reason_length+2;
+ msg_length = reason_length + 2;
}
arg.opcode = WSLAY_CONNECTION_CLOSE;
arg.msg = msg;
arg.msg_length = msg_length;
r = wslay_event_queue_msg(ctx, &arg);
- if(r == 0) {
+ if (r == 0) {
ctx->close_status |= WSLAY_CLOSE_QUEUED;
}
return r;
}
}
-static int wslay_event_queue_close_wrapper
-(wslay_event_context_ptr ctx, uint16_t status_code,
- const uint8_t *reason, size_t reason_length)
-{
+static int wslay_event_queue_close_wrapper(wslay_event_context_ptr ctx,
+ uint16_t status_code,
+ const uint8_t *reason,
+ size_t reason_length) {
int r;
ctx->read_enabled = 0;
- if((r = wslay_event_queue_close(ctx, status_code, reason, reason_length)) &&
- r != WSLAY_ERR_NO_MORE_MSG) {
+ if ((r = wslay_event_queue_close(ctx, status_code, reason, reason_length)) &&
+ r != WSLAY_ERR_NO_MORE_MSG) {
return r;
}
return 0;
}
-static int wslay_event_verify_rsv_bits(wslay_event_context_ptr ctx, uint8_t rsv)
-{
+static int wslay_event_verify_rsv_bits(wslay_event_context_ptr ctx,
+ uint8_t rsv) {
return ((rsv & ~ctx->allowed_rsv_bits) == 0);
}
int wslay_event_queue_msg(wslay_event_context_ptr ctx,
- const struct wslay_event_msg *arg)
-{
+ const struct wslay_event_msg *arg) {
return wslay_event_queue_msg_ex(ctx, arg, WSLAY_RSV_NONE);
}
int wslay_event_queue_msg_ex(wslay_event_context_ptr ctx,
- const struct wslay_event_msg *arg, uint8_t rsv)
-{
+ const struct wslay_event_msg *arg, uint8_t rsv) {
int r;
struct wslay_event_omsg *omsg;
- if(!wslay_event_is_msg_queueable(ctx)) {
+ if (!wslay_event_is_msg_queueable(ctx)) {
return WSLAY_ERR_NO_MORE_MSG;
}
/* RSV1 is not allowed for control frames */
- if((wslay_is_ctrl_frame(arg->opcode) &&
- (arg->msg_length > 125 || wslay_get_rsv1(rsv)))
- || !wslay_event_verify_rsv_bits(ctx, rsv)) {
+ if ((wslay_is_ctrl_frame(arg->opcode) &&
+ (arg->msg_length > 125 || wslay_get_rsv1(rsv))) ||
+ !wslay_event_verify_rsv_bits(ctx, rsv)) {
return WSLAY_ERR_INVALID_ARGUMENT;
}
- if((r = wslay_event_omsg_non_fragmented_init
- (&omsg, arg->opcode, rsv, arg->msg, arg->msg_length)) != 0) {
+ if ((r = wslay_event_omsg_non_fragmented_init(
+ &omsg, arg->opcode, rsv, arg->msg, arg->msg_length)) != 0) {
return r;
}
- if(wslay_is_ctrl_frame(arg->opcode)) {
- if((r = wslay_queue_push(ctx->send_ctrl_queue, omsg)) != 0) {
- return r;
- }
+ if (wslay_is_ctrl_frame(arg->opcode)) {
+ wslay_queue_push(&ctx->send_ctrl_queue, &omsg->qe);
} else {
- if((r = wslay_queue_push(ctx->send_queue, omsg)) != 0) {
- return r;
- }
+ wslay_queue_push(&ctx->send_queue, &omsg->qe);
}
++ctx->queued_msg_count;
ctx->queued_msg_length += arg->msg_length;
return 0;
}
-int wslay_event_queue_fragmented_msg
-(wslay_event_context_ptr ctx, const struct wslay_event_fragmented_msg *arg)
-{
+int wslay_event_queue_fragmented_msg(
+ wslay_event_context_ptr ctx, const struct wslay_event_fragmented_msg *arg) {
return wslay_event_queue_fragmented_msg_ex(ctx, arg, WSLAY_RSV_NONE);
}
-int wslay_event_queue_fragmented_msg_ex(wslay_event_context_ptr ctx,
- const struct wslay_event_fragmented_msg *arg, uint8_t rsv)
-{
+int wslay_event_queue_fragmented_msg_ex(
+ wslay_event_context_ptr ctx, const struct wslay_event_fragmented_msg *arg,
+ uint8_t rsv) {
int r;
struct wslay_event_omsg *omsg;
- if(!wslay_event_is_msg_queueable(ctx)) {
+ if (!wslay_event_is_msg_queueable(ctx)) {
return WSLAY_ERR_NO_MORE_MSG;
}
- if(wslay_is_ctrl_frame(arg->opcode) ||
- !wslay_event_verify_rsv_bits(ctx, rsv)) {
+ if (wslay_is_ctrl_frame(arg->opcode) ||
+ !wslay_event_verify_rsv_bits(ctx, rsv)) {
return WSLAY_ERR_INVALID_ARGUMENT;
}
- if((r = wslay_event_omsg_fragmented_init
- (&omsg, arg->opcode, rsv, arg->source, arg->read_callback)) != 0) {
- return r;
- }
- if((r = wslay_queue_push(ctx->send_queue, omsg)) != 0) {
+ if ((r = wslay_event_omsg_fragmented_init(
+ &omsg, arg->opcode, rsv, arg->source, arg->read_callback)) != 0) {
return r;
}
+ wslay_queue_push(&ctx->send_queue, &omsg->qe);
++ctx->queued_msg_count;
return 0;
}
-void wslay_event_config_set_callbacks
-(wslay_event_context_ptr ctx, const struct wslay_event_callbacks *callbacks)
-{
+void wslay_event_config_set_callbacks(
+ wslay_event_context_ptr ctx,
+ const struct wslay_event_callbacks *callbacks) {
ctx->callbacks = *callbacks;
}
-static int wslay_event_context_init
-(wslay_event_context_ptr *ctx,
- const struct wslay_event_callbacks *callbacks,
- void *user_data)
-{
+static int
+wslay_event_context_init(wslay_event_context_ptr *ctx,
+ const struct wslay_event_callbacks *callbacks,
+ void *user_data) {
int i, r;
struct wslay_frame_callbacks frame_callbacks = {
- wslay_event_frame_send_callback,
- wslay_event_frame_recv_callback,
- wslay_event_frame_genmask_callback
- };
- *ctx = (wslay_event_context_ptr)malloc(sizeof(struct wslay_event_context));
- if(!*ctx) {
+ wslay_event_frame_send_callback, wslay_event_frame_recv_callback,
+ wslay_event_frame_genmask_callback};
+ *ctx = calloc(1, sizeof(struct wslay_event_context));
+ if (!*ctx) {
return WSLAY_ERR_NOMEM;
}
- memset(*ctx, 0, sizeof(struct wslay_event_context));
wslay_event_config_set_callbacks(*ctx, callbacks);
(*ctx)->user_data = user_data;
(*ctx)->frame_user_data.ctx = *ctx;
(*ctx)->frame_user_data.user_data = user_data;
- if((r = wslay_frame_context_init(&(*ctx)->frame_ctx, &frame_callbacks,
- &(*ctx)->frame_user_data)) != 0) {
+ if ((r = wslay_frame_context_init(&(*ctx)->frame_ctx, &frame_callbacks,
+ &(*ctx)->frame_user_data)) != 0) {
wslay_event_context_free(*ctx);
return r;
}
(*ctx)->read_enabled = (*ctx)->write_enabled = 1;
- (*ctx)->send_queue = wslay_queue_new();
- if(!(*ctx)->send_queue) {
- wslay_event_context_free(*ctx);
- return WSLAY_ERR_NOMEM;
- }
- (*ctx)->send_ctrl_queue = wslay_queue_new();
- if(!(*ctx)->send_ctrl_queue) {
- wslay_event_context_free(*ctx);
- return WSLAY_ERR_NOMEM;
- }
+ wslay_queue_init(&(*ctx)->send_queue);
+ wslay_queue_init(&(*ctx)->send_ctrl_queue);
(*ctx)->queued_msg_count = 0;
(*ctx)->queued_msg_length = 0;
- for(i = 0; i < 2; ++i) {
+ for (i = 0; i < 2; ++i) {
+ wslay_queue_init(&(*ctx)->imsgs[i].chunks);
wslay_event_imsg_reset(&(*ctx)->imsgs[i]);
- (*ctx)->imsgs[i].chunks = wslay_queue_new();
- if(!(*ctx)->imsgs[i].chunks) {
- wslay_event_context_free(*ctx);
- return WSLAY_ERR_NOMEM;
- }
}
(*ctx)->imsg = &(*ctx)->imsgs[0];
(*ctx)->obufmark = (*ctx)->obuflimit = (*ctx)->obuf;
(*ctx)->status_code_sent = WSLAY_CODE_ABNORMAL_CLOSURE;
(*ctx)->status_code_recv = WSLAY_CODE_ABNORMAL_CLOSURE;
- (*ctx)->max_recv_msg_length = (1u << 31)-1;
+ (*ctx)->max_recv_msg_length = (1u << 31) - 1;
return 0;
}
-int wslay_event_context_server_init
-(wslay_event_context_ptr *ctx,
- const struct wslay_event_callbacks *callbacks,
- void *user_data)
-{
+int wslay_event_context_server_init(
+ wslay_event_context_ptr *ctx, const struct wslay_event_callbacks *callbacks,
+ void *user_data) {
int r;
- if((r = wslay_event_context_init(ctx, callbacks, user_data)) != 0) {
+ if ((r = wslay_event_context_init(ctx, callbacks, user_data)) != 0) {
return r;
}
(*ctx)->server = 1;
return 0;
}
-int wslay_event_context_client_init
-(wslay_event_context_ptr *ctx,
- const struct wslay_event_callbacks *callbacks,
- void *user_data)
-{
+int wslay_event_context_client_init(
+ wslay_event_context_ptr *ctx, const struct wslay_event_callbacks *callbacks,
+ void *user_data) {
int r;
- if((r = wslay_event_context_init(ctx, callbacks, user_data)) != 0) {
+ if ((r = wslay_event_context_init(ctx, callbacks, user_data)) != 0) {
return r;
}
(*ctx)->server = 0;
return 0;
}
-void wslay_event_context_free(wslay_event_context_ptr ctx)
-{
+void wslay_event_context_free(wslay_event_context_ptr ctx) {
int i;
- if(!ctx) {
+ if (!ctx) {
return;
}
- for(i = 0; i < 2; ++i) {
+ for (i = 0; i < 2; ++i) {
wslay_event_imsg_chunks_free(&ctx->imsgs[i]);
- wslay_queue_free(ctx->imsgs[i].chunks);
+ wslay_queue_deinit(&ctx->imsgs[i].chunks);
}
- if(ctx->send_queue) {
- while(!wslay_queue_empty(ctx->send_queue)) {
- wslay_event_omsg_free(wslay_queue_top(ctx->send_queue));
- wslay_queue_pop(ctx->send_queue);
- }
- wslay_queue_free(ctx->send_queue);
+
+ while (!wslay_queue_empty(&ctx->send_queue)) {
+ struct wslay_event_omsg *omsg = wslay_struct_of(
+ wslay_queue_top(&ctx->send_queue), struct wslay_event_omsg, qe);
+ wslay_queue_pop(&ctx->send_queue);
+ wslay_event_omsg_free(omsg);
}
- if(ctx->send_ctrl_queue) {
- while(!wslay_queue_empty(ctx->send_ctrl_queue)) {
- wslay_event_omsg_free(wslay_queue_top(ctx->send_ctrl_queue));
- wslay_queue_pop(ctx->send_ctrl_queue);
- }
- wslay_queue_free(ctx->send_ctrl_queue);
+ wslay_queue_deinit(&ctx->send_queue);
+
+ while (!wslay_queue_empty(&ctx->send_ctrl_queue)) {
+ struct wslay_event_omsg *omsg = wslay_struct_of(
+ wslay_queue_top(&ctx->send_ctrl_queue), struct wslay_event_omsg, qe);
+ wslay_queue_pop(&ctx->send_ctrl_queue);
+ wslay_event_omsg_free(omsg);
}
+ wslay_queue_deinit(&ctx->send_ctrl_queue);
+
wslay_frame_context_free(ctx->frame_ctx);
wslay_event_omsg_free(ctx->omsg);
free(ctx);
}
-static void wslay_event_call_on_frame_recv_start_callback
-(wslay_event_context_ptr ctx, const struct wslay_frame_iocb *iocb)
-{
- if(ctx->callbacks.on_frame_recv_start_callback) {
+static void wslay_event_call_on_frame_recv_start_callback(
+ wslay_event_context_ptr ctx, const struct wslay_frame_iocb *iocb) {
+ if (ctx->callbacks.on_frame_recv_start_callback) {
struct wslay_event_on_frame_recv_start_arg arg;
arg.fin = iocb->fin;
arg.rsv = iocb->rsv;
@@ -532,10 +469,9 @@ static void wslay_event_call_on_frame_recv_start_callback
}
}
-static void wslay_event_call_on_frame_recv_chunk_callback
-(wslay_event_context_ptr ctx, const struct wslay_frame_iocb *iocb)
-{
- if(ctx->callbacks.on_frame_recv_chunk_callback) {
+static void wslay_event_call_on_frame_recv_chunk_callback(
+ wslay_event_context_ptr ctx, const struct wslay_frame_iocb *iocb) {
+ if (ctx->callbacks.on_frame_recv_chunk_callback) {
struct wslay_event_on_frame_recv_chunk_arg arg;
arg.data = iocb->data;
arg.data_length = iocb->data_length;
@@ -543,205 +479,202 @@ static void wslay_event_call_on_frame_recv_chunk_callback
}
}
-static void wslay_event_call_on_frame_recv_end_callback
-(wslay_event_context_ptr ctx)
-{
- if(ctx->callbacks.on_frame_recv_end_callback) {
+static void
+wslay_event_call_on_frame_recv_end_callback(wslay_event_context_ptr ctx) {
+ if (ctx->callbacks.on_frame_recv_end_callback) {
ctx->callbacks.on_frame_recv_end_callback(ctx, ctx->user_data);
}
}
-static int wslay_event_is_valid_status_code(uint16_t status_code)
-{
- return (1000 <= status_code && status_code <= 1011 &&
- status_code != 1004 && status_code != 1005 && status_code != 1006) ||
- (3000 <= status_code && status_code <= 4999);
+static int wslay_event_is_valid_status_code(uint16_t status_code) {
+ return (1000 <= status_code && status_code <= 1011 && status_code != 1004 &&
+ status_code != 1005 && status_code != 1006) ||
+ (3000 <= status_code && status_code <= 4999);
}
-static int wslay_event_config_get_no_buffering(wslay_event_context_ptr ctx)
-{
+static int wslay_event_config_get_no_buffering(wslay_event_context_ptr ctx) {
return (ctx->config & WSLAY_CONFIG_NO_BUFFERING) > 0;
}
-int wslay_event_recv(wslay_event_context_ptr ctx)
-{
+int wslay_event_recv(wslay_event_context_ptr ctx) {
struct wslay_frame_iocb iocb;
ssize_t r;
- while(ctx->read_enabled) {
+ while (ctx->read_enabled) {
memset(&iocb, 0, sizeof(iocb));
r = wslay_frame_recv(ctx->frame_ctx, &iocb);
- if(r >= 0) {
+ if (r >= 0) {
int new_frame = 0;
/* RSV1 is not allowed on control and continuation frames */
- if((!wslay_event_verify_rsv_bits(ctx, iocb.rsv)) ||
- (wslay_get_rsv1(iocb.rsv) && (wslay_is_ctrl_frame(iocb.opcode) ||
- iocb.opcode == WSLAY_CONTINUATION_FRAME)) ||
- (ctx->server && !iocb.mask) || (!ctx->server && iocb.mask)) {
- if((r = wslay_event_queue_close_wrapper
- (ctx, WSLAY_CODE_PROTOCOL_ERROR, NULL, 0)) != 0) {
- return r;
+ if ((!wslay_event_verify_rsv_bits(ctx, iocb.rsv)) ||
+ (wslay_get_rsv1(iocb.rsv) &&
+ (wslay_is_ctrl_frame(iocb.opcode) ||
+ iocb.opcode == WSLAY_CONTINUATION_FRAME)) ||
+ (ctx->server && !iocb.mask) || (!ctx->server && iocb.mask)) {
+ if ((r = wslay_event_queue_close_wrapper(ctx, WSLAY_CODE_PROTOCOL_ERROR,
+ NULL, 0)) != 0) {
+ return (int)r;
}
break;
}
- if(ctx->imsg->opcode == 0xffu) {
- if(iocb.opcode == WSLAY_TEXT_FRAME ||
- iocb.opcode == WSLAY_BINARY_FRAME ||
- iocb.opcode == WSLAY_CONNECTION_CLOSE ||
- iocb.opcode == WSLAY_PING ||
- iocb.opcode == WSLAY_PONG) {
+ if (ctx->imsg->opcode == 0xffu) {
+ if (iocb.opcode == WSLAY_TEXT_FRAME ||
+ iocb.opcode == WSLAY_BINARY_FRAME ||
+ iocb.opcode == WSLAY_CONNECTION_CLOSE ||
+ iocb.opcode == WSLAY_PING || iocb.opcode == WSLAY_PONG) {
wslay_event_imsg_set(ctx->imsg, iocb.fin, iocb.rsv, iocb.opcode);
new_frame = 1;
} else {
- if((r = wslay_event_queue_close_wrapper
- (ctx, WSLAY_CODE_PROTOCOL_ERROR, NULL, 0)) != 0) {
- return r;
+ if ((r = wslay_event_queue_close_wrapper(
+ ctx, WSLAY_CODE_PROTOCOL_ERROR, NULL, 0)) != 0) {
+ return (int)r;
}
break;
}
- } else if(ctx->ipayloadlen == 0 && ctx->ipayloadoff == 0) {
- if(iocb.opcode == WSLAY_CONTINUATION_FRAME) {
+ } else if (ctx->ipayloadlen == 0 && ctx->ipayloadoff == 0) {
+ if (iocb.opcode == WSLAY_CONTINUATION_FRAME) {
ctx->imsg->fin = iocb.fin;
- } else if(iocb.opcode == WSLAY_CONNECTION_CLOSE ||
- iocb.opcode == WSLAY_PING ||
- iocb.opcode == WSLAY_PONG) {
+ } else if (iocb.opcode == WSLAY_CONNECTION_CLOSE ||
+ iocb.opcode == WSLAY_PING || iocb.opcode == WSLAY_PONG) {
ctx->imsg = &ctx->imsgs[1];
wslay_event_imsg_set(ctx->imsg, iocb.fin, iocb.rsv, iocb.opcode);
} else {
- if((r = wslay_event_queue_close_wrapper
- (ctx, WSLAY_CODE_PROTOCOL_ERROR, NULL, 0)) != 0) {
- return r;
+ if ((r = wslay_event_queue_close_wrapper(
+ ctx, WSLAY_CODE_PROTOCOL_ERROR, NULL, 0)) != 0) {
+ return (int)r;
}
break;
}
new_frame = 1;
}
- if(new_frame) {
- if(ctx->imsg->msg_length+iocb.payload_length >
- ctx->max_recv_msg_length) {
- if((r = wslay_event_queue_close_wrapper
- (ctx, WSLAY_CODE_MESSAGE_TOO_BIG, NULL, 0)) != 0) {
- return r;
+ if (new_frame) {
+ if (ctx->imsg->msg_length + iocb.payload_length >
+ ctx->max_recv_msg_length) {
+ if ((r = wslay_event_queue_close_wrapper(
+ ctx, WSLAY_CODE_MESSAGE_TOO_BIG, NULL, 0)) != 0) {
+ return (int)r;
}
break;
}
ctx->ipayloadlen = iocb.payload_length;
wslay_event_call_on_frame_recv_start_callback(ctx, &iocb);
- if(!wslay_event_config_get_no_buffering(ctx) ||
- wslay_is_ctrl_frame(iocb.opcode)) {
- if((r = wslay_event_imsg_append_chunk(ctx->imsg,
- iocb.payload_length)) != 0) {
+ if (!wslay_event_config_get_no_buffering(ctx) ||
+ wslay_is_ctrl_frame(iocb.opcode)) {
+ if ((r = wslay_event_imsg_append_chunk(ctx->imsg,
+ iocb.payload_length)) != 0) {
ctx->read_enabled = 0;
- return r;
+ return (int)r;
}
}
}
/* If RSV1 bit is set then it is too early for utf-8 validation */
- if((!wslay_get_rsv1(ctx->imsg->rsv) &&
- ctx->imsg->opcode == WSLAY_TEXT_FRAME) ||
- ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE) {
+ if ((!wslay_get_rsv1(ctx->imsg->rsv) &&
+ ctx->imsg->opcode == WSLAY_TEXT_FRAME) ||
+ ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE) {
size_t i;
- if(ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE) {
+ if (ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE) {
i = 2;
} else {
i = 0;
}
- for(; i < iocb.data_length; ++i) {
+ for (; i < iocb.data_length; ++i) {
uint32_t codep;
- if(decode(&ctx->imsg->utf8state, &codep,
- iocb.data[i]) == UTF8_REJECT) {
- if((r = wslay_event_queue_close_wrapper
- (ctx, WSLAY_CODE_INVALID_FRAME_PAYLOAD_DATA, NULL, 0)) != 0) {
- return r;
+ if (decode(&ctx->imsg->utf8state, &codep, iocb.data[i]) ==
+ UTF8_REJECT) {
+ if ((r = wslay_event_queue_close_wrapper(
+ ctx, WSLAY_CODE_INVALID_FRAME_PAYLOAD_DATA, NULL, 0)) !=
+ 0) {
+ return (int)r;
}
break;
}
}
}
- if(ctx->imsg->utf8state == UTF8_REJECT) {
+ if (ctx->imsg->utf8state == UTF8_REJECT) {
break;
}
wslay_event_call_on_frame_recv_chunk_callback(ctx, &iocb);
- if(iocb.data_length > 0) {
- if(!wslay_event_config_get_no_buffering(ctx) ||
- wslay_is_ctrl_frame(iocb.opcode)) {
+ if (iocb.data_length > 0) {
+ if (!wslay_event_config_get_no_buffering(ctx) ||
+ wslay_is_ctrl_frame(iocb.opcode)) {
struct wslay_event_byte_chunk *chunk;
- chunk = wslay_queue_tail(ctx->imsg->chunks);
- wslay_event_byte_chunk_copy(chunk, ctx->ipayloadoff,
- iocb.data, iocb.data_length);
+ chunk = wslay_struct_of(wslay_queue_tail(&ctx->imsg->chunks),
+ struct wslay_event_byte_chunk, qe);
+ wslay_event_byte_chunk_copy(chunk, ctx->ipayloadoff, iocb.data,
+ iocb.data_length);
}
ctx->ipayloadoff += iocb.data_length;
}
- if(ctx->ipayloadoff == ctx->ipayloadlen) {
- if(ctx->imsg->fin &&
- (ctx->imsg->opcode == WSLAY_TEXT_FRAME ||
- ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE) &&
- ctx->imsg->utf8state != UTF8_ACCEPT) {
- if((r = wslay_event_queue_close_wrapper
- (ctx, WSLAY_CODE_INVALID_FRAME_PAYLOAD_DATA, NULL, 0)) != 0) {
- return r;
+ if (ctx->ipayloadoff == ctx->ipayloadlen) {
+ if (ctx->imsg->fin &&
+ (ctx->imsg->opcode == WSLAY_TEXT_FRAME ||
+ ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE) &&
+ ctx->imsg->utf8state != UTF8_ACCEPT) {
+ if ((r = wslay_event_queue_close_wrapper(
+ ctx, WSLAY_CODE_INVALID_FRAME_PAYLOAD_DATA, NULL, 0)) != 0) {
+ return (int)r;
}
break;
}
wslay_event_call_on_frame_recv_end_callback(ctx);
- if(ctx->imsg->fin) {
- if(ctx->callbacks.on_msg_recv_callback ||
- ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE ||
- ctx->imsg->opcode == WSLAY_PING) {
+ if (ctx->imsg->fin) {
+ if (ctx->callbacks.on_msg_recv_callback ||
+ ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE ||
+ ctx->imsg->opcode == WSLAY_PING) {
struct wslay_event_on_msg_recv_arg arg;
uint16_t status_code = 0;
uint8_t *msg = NULL;
size_t msg_length = 0;
- if(!wslay_event_config_get_no_buffering(ctx) ||
- wslay_is_ctrl_frame(iocb.opcode)) {
- msg = wslay_event_flatten_queue(ctx->imsg->chunks,
+ if (!wslay_event_config_get_no_buffering(ctx) ||
+ wslay_is_ctrl_frame(iocb.opcode)) {
+ msg = wslay_event_flatten_queue(&ctx->imsg->chunks,
ctx->imsg->msg_length);
- if(ctx->imsg->msg_length && !msg) {
+ if (ctx->imsg->msg_length && !msg) {
ctx->read_enabled = 0;
return WSLAY_ERR_NOMEM;
}
msg_length = ctx->imsg->msg_length;
}
- if(ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE) {
+ if (ctx->imsg->opcode == WSLAY_CONNECTION_CLOSE) {
const uint8_t *reason;
size_t reason_length;
- if(ctx->imsg->msg_length >= 2) {
+ if (ctx->imsg->msg_length >= 2) {
memcpy(&status_code, msg, 2);
status_code = ntohs(status_code);
- if(!wslay_event_is_valid_status_code(status_code)) {
+ if (!wslay_event_is_valid_status_code(status_code)) {
free(msg);
- if((r = wslay_event_queue_close_wrapper
- (ctx, WSLAY_CODE_PROTOCOL_ERROR, NULL, 0)) != 0) {
- return r;
+ if ((r = wslay_event_queue_close_wrapper(
+ ctx, WSLAY_CODE_PROTOCOL_ERROR, NULL, 0)) != 0) {
+ return (int)r;
}
break;
}
- reason = msg+2;
- reason_length = ctx->imsg->msg_length-2;
+ reason = msg + 2;
+ reason_length = ctx->imsg->msg_length - 2;
} else {
reason = NULL;
reason_length = 0;
}
ctx->close_status |= WSLAY_CLOSE_RECEIVED;
ctx->status_code_recv =
- status_code == 0 ? WSLAY_CODE_NO_STATUS_RCVD : status_code;
- if((r = wslay_event_queue_close_wrapper
- (ctx, status_code, reason, reason_length)) != 0) {
+ status_code == 0 ? WSLAY_CODE_NO_STATUS_RCVD : status_code;
+ if ((r = wslay_event_queue_close_wrapper(ctx, status_code, reason,
+ reason_length)) != 0) {
free(msg);
- return r;
+ return (int)r;
}
- } else if(ctx->imsg->opcode == WSLAY_PING) {
+ } else if (ctx->imsg->opcode == WSLAY_PING) {
struct wslay_event_msg pong_arg;
pong_arg.opcode = WSLAY_PONG;
pong_arg.msg = msg;
pong_arg.msg_length = ctx->imsg->msg_length;
- if((r = wslay_event_queue_msg(ctx, &pong_arg)) &&
- r != WSLAY_ERR_NO_MORE_MSG) {
+ if ((r = wslay_event_queue_msg(ctx, &pong_arg)) &&
+ r != WSLAY_ERR_NO_MORE_MSG) {
ctx->read_enabled = 0;
free(msg);
- return r;
+ return (int)r;
}
}
- if(ctx->callbacks.on_msg_recv_callback) {
+ if (ctx->callbacks.on_msg_recv_callback) {
arg.rsv = ctx->imsg->rsv;
arg.opcode = ctx->imsg->opcode;
arg.msg = msg;
@@ -753,17 +686,17 @@ int wslay_event_recv(wslay_event_context_ptr ctx)
free(msg);
}
wslay_event_imsg_reset(ctx->imsg);
- if(ctx->imsg == &ctx->imsgs[1]) {
+ if (ctx->imsg == &ctx->imsgs[1]) {
ctx->imsg = &ctx->imsgs[0];
}
}
ctx->ipayloadlen = ctx->ipayloadoff = 0;
}
} else {
- if(r != WSLAY_ERR_WANT_READ ||
- (ctx->error != WSLAY_ERR_WOULDBLOCK && ctx->error != 0)) {
- if((r = wslay_event_queue_close_wrapper(ctx, 0, NULL, 0)) != 0) {
- return r;
+ if (r != WSLAY_ERR_WANT_READ ||
+ (ctx->error != WSLAY_ERR_WOULDBLOCK && ctx->error != 0)) {
+ if ((r = wslay_event_queue_close_wrapper(ctx, 0, NULL, 0)) != 0) {
+ return (int)r;
}
return WSLAY_ERR_CALLBACK_FAILURE;
}
@@ -773,26 +706,25 @@ int wslay_event_recv(wslay_event_context_ptr ctx)
return 0;
}
-static void wslay_event_on_non_fragmented_msg_popped
-(wslay_event_context_ptr ctx)
-{
+static void
+wslay_event_on_non_fragmented_msg_popped(wslay_event_context_ptr ctx) {
ctx->omsg->fin = 1;
ctx->opayloadlen = ctx->omsg->data_length;
ctx->opayloadoff = 0;
}
-static struct wslay_event_omsg* wslay_event_send_ctrl_queue_pop
-(wslay_event_context_ptr ctx)
-{
+static struct wslay_event_omsg *
+wslay_event_send_ctrl_queue_pop(wslay_event_context_ptr ctx) {
/*
* If Close control frame is queued, we don't send any control frame
* other than Close.
*/
- if(ctx->close_status & WSLAY_CLOSE_QUEUED) {
- while(!wslay_queue_empty(ctx->send_ctrl_queue)) {
- struct wslay_event_omsg *msg = wslay_queue_top(ctx->send_ctrl_queue);
- wslay_queue_pop(ctx->send_ctrl_queue);
- if(msg->opcode == WSLAY_CONNECTION_CLOSE) {
+ if (ctx->close_status & WSLAY_CLOSE_QUEUED) {
+ while (!wslay_queue_empty(&ctx->send_ctrl_queue)) {
+ struct wslay_event_omsg *msg = wslay_struct_of(
+ wslay_queue_top(&ctx->send_ctrl_queue), struct wslay_event_omsg, qe);
+ wslay_queue_pop(&ctx->send_ctrl_queue);
+ if (msg->opcode == WSLAY_CONNECTION_CLOSE) {
return msg;
} else {
wslay_event_omsg_free(msg);
@@ -800,71 +732,73 @@ static struct wslay_event_omsg* wslay_event_send_ctrl_queue_pop
}
return NULL;
} else {
- struct wslay_event_omsg *msg = wslay_queue_top(ctx->send_ctrl_queue);
- wslay_queue_pop(ctx->send_ctrl_queue);
+ struct wslay_event_omsg *msg = wslay_struct_of(
+ wslay_queue_top(&ctx->send_ctrl_queue), struct wslay_event_omsg, qe);
+ wslay_queue_pop(&ctx->send_ctrl_queue);
return msg;
}
}
-int wslay_event_send(wslay_event_context_ptr ctx)
-{
+int wslay_event_send(wslay_event_context_ptr ctx) {
struct wslay_frame_iocb iocb;
ssize_t r;
- while(ctx->write_enabled &&
- (!wslay_queue_empty(ctx->send_queue) ||
- !wslay_queue_empty(ctx->send_ctrl_queue) || ctx->omsg)) {
- if(!ctx->omsg) {
- if(wslay_queue_empty(ctx->send_ctrl_queue)) {
- ctx->omsg = wslay_queue_top(ctx->send_queue);
- wslay_queue_pop(ctx->send_queue);
+ while (ctx->write_enabled &&
+ (!wslay_queue_empty(&ctx->send_queue) ||
+ !wslay_queue_empty(&ctx->send_ctrl_queue) || ctx->omsg)) {
+ if (!ctx->omsg) {
+ if (wslay_queue_empty(&ctx->send_ctrl_queue)) {
+ ctx->omsg = wslay_struct_of(wslay_queue_top(&ctx->send_queue),
+ struct wslay_event_omsg, qe);
+ wslay_queue_pop(&ctx->send_queue);
} else {
ctx->omsg = wslay_event_send_ctrl_queue_pop(ctx);
- if(ctx->omsg == NULL) {
+ if (ctx->omsg == NULL) {
break;
}
}
- if(ctx->omsg->type == WSLAY_NON_FRAGMENTED) {
+ if (ctx->omsg->type == WSLAY_NON_FRAGMENTED) {
wslay_event_on_non_fragmented_msg_popped(ctx);
}
- } else if(!wslay_is_ctrl_frame(ctx->omsg->opcode) &&
- ctx->frame_ctx->ostate == PREP_HEADER &&
- !wslay_queue_empty(ctx->send_ctrl_queue)) {
- if((r = wslay_queue_push_front(ctx->send_queue, ctx->omsg)) != 0) {
- ctx->write_enabled = 0;
- return r;
- }
+ } else if (!wslay_is_ctrl_frame(ctx->omsg->opcode) &&
+ ctx->frame_ctx->ostate == PREP_HEADER &&
+ !wslay_queue_empty(&ctx->send_ctrl_queue)) {
+ wslay_queue_push_front(&ctx->send_queue, &ctx->omsg->qe);
ctx->omsg = wslay_event_send_ctrl_queue_pop(ctx);
- if(ctx->omsg == NULL) {
+ if (ctx->omsg == NULL) {
break;
}
/* ctrl message has WSLAY_NON_FRAGMENTED */
wslay_event_on_non_fragmented_msg_popped(ctx);
}
- if(ctx->omsg->type == WSLAY_NON_FRAGMENTED) {
+ if (ctx->omsg->type == WSLAY_NON_FRAGMENTED) {
memset(&iocb, 0, sizeof(iocb));
iocb.fin = 1;
iocb.opcode = ctx->omsg->opcode;
iocb.rsv = ctx->omsg->rsv;
- iocb.mask = ctx->server^1;
- iocb.data = ctx->omsg->data+ctx->opayloadoff;
- iocb.data_length = ctx->opayloadlen-ctx->opayloadoff;
+ iocb.mask = ctx->server ^ 1;
+ iocb.data = ctx->omsg->data;
+ iocb.data_length = ctx->opayloadlen;
+ if (ctx->opayloadoff) {
+ iocb.data += ctx->opayloadoff;
+ iocb.data_length -= ctx->opayloadoff;
+ }
iocb.payload_length = ctx->opayloadlen;
r = wslay_frame_send(ctx->frame_ctx, &iocb);
- if(r >= 0) {
- ctx->opayloadoff += r;
- if(ctx->opayloadoff == ctx->opayloadlen) {
+ if (r >= 0) {
+ ctx->opayloadoff += (uint64_t)r;
+ if (ctx->opayloadoff == ctx->opayloadlen) {
--ctx->queued_msg_count;
ctx->queued_msg_length -= ctx->omsg->data_length;
- if(ctx->omsg->opcode == WSLAY_CONNECTION_CLOSE) {
+ if (ctx->omsg->opcode == WSLAY_CONNECTION_CLOSE) {
uint16_t status_code = 0;
ctx->write_enabled = 0;
ctx->close_status |= WSLAY_CLOSE_SENT;
- if(ctx->omsg->data_length >= 2) {
+ if (ctx->omsg->data_length >= 2) {
memcpy(&status_code, ctx->omsg->data, 2);
status_code = ntohs(status_code);
}
ctx->status_code_sent =
- status_code == 0 ? WSLAY_CODE_NO_STATUS_RCVD : status_code;
+ status_code == 0 ? WSLAY_CODE_NO_STATUS_RCVD : status_code;
}
wslay_event_omsg_free(ctx->omsg);
ctx->omsg = NULL;
@@ -872,30 +806,29 @@ int wslay_event_send(wslay_event_context_ptr ctx)
break;
}
} else {
- if(r != WSLAY_ERR_WANT_WRITE ||
- (ctx->error != WSLAY_ERR_WOULDBLOCK && ctx->error != 0)) {
+ if (r != WSLAY_ERR_WANT_WRITE ||
+ (ctx->error != WSLAY_ERR_WOULDBLOCK && ctx->error != 0)) {
ctx->write_enabled = 0;
return WSLAY_ERR_CALLBACK_FAILURE;
}
break;
}
} else {
- if(ctx->omsg->fin == 0 && ctx->obuflimit == ctx->obufmark) {
+ if (ctx->omsg->fin == 0 && ctx->obuflimit == ctx->obufmark) {
int eof = 0;
r = ctx->omsg->read_callback(ctx, ctx->obuf, sizeof(ctx->obuf),
- &ctx->omsg->source,
- &eof, ctx->user_data);
- if(r == 0 && eof == 0) {
+ &ctx->omsg->source, &eof, ctx->user_data);
+ if (r == 0 && eof == 0) {
break;
- } else if(r < 0) {
+ } else if (r < 0) {
ctx->write_enabled = 0;
return WSLAY_ERR_CALLBACK_FAILURE;
}
- ctx->obuflimit = ctx->obuf+r;
- if(eof) {
+ ctx->obuflimit = ctx->obuf + r;
+ if (eof) {
ctx->omsg->fin = 1;
}
- ctx->opayloadlen = r;
+ ctx->opayloadlen = (uint64_t)r;
ctx->opayloadoff = 0;
}
memset(&iocb, 0, sizeof(iocb));
@@ -904,29 +837,28 @@ int wslay_event_send(wslay_event_context_ptr ctx)
iocb.rsv = ctx->omsg->rsv;
iocb.mask = ctx->server ? 0 : 1;
iocb.data = ctx->obufmark;
- iocb.data_length = ctx->obuflimit-ctx->obufmark;
+ iocb.data_length = (size_t)(ctx->obuflimit - ctx->obufmark);
iocb.payload_length = ctx->opayloadlen;
r = wslay_frame_send(ctx->frame_ctx, &iocb);
- if(r >= 0) {
+ if (r >= 0) {
ctx->obufmark += r;
- if(ctx->obufmark == ctx->obuflimit) {
+ if (ctx->obufmark == ctx->obuflimit) {
ctx->obufmark = ctx->obuflimit = ctx->obuf;
- if(ctx->omsg->fin) {
+ if (ctx->omsg->fin) {
--ctx->queued_msg_count;
wslay_event_omsg_free(ctx->omsg);
ctx->omsg = NULL;
} else {
ctx->omsg->opcode = WSLAY_CONTINUATION_FRAME;
/* RSV1 is not set on continuation frames */
- ctx->omsg->rsv = ctx->omsg->rsv & ~WSLAY_RSV1_BIT;
+ ctx->omsg->rsv = (uint8_t)(ctx->omsg->rsv & ~WSLAY_RSV1_BIT);
}
} else {
break;
}
} else {
- if(r != WSLAY_ERR_WANT_WRITE ||
- (ctx->error != WSLAY_ERR_WOULDBLOCK &&
- ctx->error != 0)) {
+ if (r != WSLAY_ERR_WANT_WRITE ||
+ (ctx->error != WSLAY_ERR_WOULDBLOCK && ctx->error != 0)) {
ctx->write_enabled = 0;
return WSLAY_ERR_CALLBACK_FAILURE;
}
@@ -937,91 +869,214 @@ int wslay_event_send(wslay_event_context_ptr ctx)
return 0;
}
-void wslay_event_set_error(wslay_event_context_ptr ctx, int val)
-{
+ssize_t wslay_event_write(wslay_event_context_ptr ctx, uint8_t *buf,
+ size_t buflen) {
+ struct wslay_frame_iocb iocb;
+ ssize_t r;
+ uint8_t *buf_last = buf;
+ size_t wpayloadlen;
+ while (ctx->write_enabled &&
+ (!wslay_queue_empty(&ctx->send_queue) ||
+ !wslay_queue_empty(&ctx->send_ctrl_queue) || ctx->omsg)) {
+ if (!ctx->omsg) {
+ if (wslay_queue_empty(&ctx->send_ctrl_queue)) {
+ ctx->omsg = wslay_struct_of(wslay_queue_top(&ctx->send_queue),
+ struct wslay_event_omsg, qe);
+ wslay_queue_pop(&ctx->send_queue);
+ } else {
+ ctx->omsg = wslay_event_send_ctrl_queue_pop(ctx);
+ if (ctx->omsg == NULL) {
+ break;
+ }
+ }
+ if (ctx->omsg->type == WSLAY_NON_FRAGMENTED) {
+ wslay_event_on_non_fragmented_msg_popped(ctx);
+ }
+ } else if (!wslay_is_ctrl_frame(ctx->omsg->opcode) &&
+ ctx->frame_ctx->ostate == PREP_HEADER &&
+ !wslay_queue_empty(&ctx->send_ctrl_queue)) {
+ wslay_queue_push_front(&ctx->send_queue, &ctx->omsg->qe);
+ ctx->omsg = wslay_event_send_ctrl_queue_pop(ctx);
+ if (ctx->omsg == NULL) {
+ break;
+ }
+ /* ctrl message has WSLAY_NON_FRAGMENTED */
+ wslay_event_on_non_fragmented_msg_popped(ctx);
+ }
+ if (ctx->omsg->type == WSLAY_NON_FRAGMENTED) {
+ memset(&iocb, 0, sizeof(iocb));
+ iocb.fin = 1;
+ iocb.opcode = ctx->omsg->opcode;
+ iocb.rsv = ctx->omsg->rsv;
+ iocb.mask = ctx->server ^ 1;
+ iocb.data = ctx->omsg->data;
+ iocb.data_length = ctx->opayloadlen;
+ if (ctx->opayloadoff) {
+ iocb.data += ctx->opayloadoff;
+ iocb.data_length -= ctx->opayloadoff;
+ }
+ iocb.payload_length = ctx->opayloadlen;
+ r = wslay_frame_write(ctx->frame_ctx, &iocb, buf_last, buflen,
+ &wpayloadlen);
+ if (r > 0) {
+ assert((size_t)r <= buflen);
+
+ buf_last += r;
+ buflen -= (size_t)r;
+
+ ctx->opayloadoff += wpayloadlen;
+ if (ctx->opayloadoff == ctx->opayloadlen) {
+ --ctx->queued_msg_count;
+ ctx->queued_msg_length -= ctx->omsg->data_length;
+ if (ctx->omsg->opcode == WSLAY_CONNECTION_CLOSE) {
+ uint16_t status_code = 0;
+ ctx->write_enabled = 0;
+ ctx->close_status |= WSLAY_CLOSE_SENT;
+ if (ctx->omsg->data_length >= 2) {
+ memcpy(&status_code, ctx->omsg->data, 2);
+ status_code = ntohs(status_code);
+ }
+ ctx->status_code_sent =
+ status_code == 0 ? WSLAY_CODE_NO_STATUS_RCVD : status_code;
+ }
+ wslay_event_omsg_free(ctx->omsg);
+ ctx->omsg = NULL;
+ } else {
+ break;
+ }
+ } else if (r == 0) {
+ return buf_last - buf;
+ } else {
+ return WSLAY_ERR_CALLBACK_FAILURE;
+ }
+ } else {
+ if (ctx->omsg->fin == 0 && ctx->obuflimit == ctx->obufmark) {
+ int eof = 0;
+ r = ctx->omsg->read_callback(ctx, ctx->obuf, sizeof(ctx->obuf),
+ &ctx->omsg->source, &eof, ctx->user_data);
+ if (r == 0 && eof == 0) {
+ break;
+ } else if (r < 0) {
+ ctx->write_enabled = 0;
+ return WSLAY_ERR_CALLBACK_FAILURE;
+ }
+ ctx->obuflimit = ctx->obuf + r;
+ if (eof) {
+ ctx->omsg->fin = 1;
+ }
+ ctx->opayloadlen = (uint64_t)r;
+ ctx->opayloadoff = 0;
+ }
+ memset(&iocb, 0, sizeof(iocb));
+ iocb.fin = ctx->omsg->fin;
+ iocb.opcode = ctx->omsg->opcode;
+ iocb.rsv = ctx->omsg->rsv;
+ iocb.mask = ctx->server ? 0 : 1;
+ iocb.data = ctx->obufmark;
+ iocb.data_length = (size_t)(ctx->obuflimit - ctx->obufmark);
+ iocb.payload_length = ctx->opayloadlen;
+ r = wslay_frame_write(ctx->frame_ctx, &iocb, buf_last, buflen,
+ &wpayloadlen);
+ if (r > 0) {
+ assert((size_t)r <= buflen);
+
+ buf_last += r;
+ buflen -= (size_t)r;
+
+ ctx->obufmark += wpayloadlen;
+ if (ctx->obufmark == ctx->obuflimit) {
+ ctx->obufmark = ctx->obuflimit = ctx->obuf;
+ if (ctx->omsg->fin) {
+ --ctx->queued_msg_count;
+ wslay_event_omsg_free(ctx->omsg);
+ ctx->omsg = NULL;
+ } else {
+ ctx->omsg->opcode = WSLAY_CONTINUATION_FRAME;
+ /* RSV1 is not set on continuation frames */
+ ctx->omsg->rsv = (uint8_t)(ctx->omsg->rsv & ~WSLAY_RSV1_BIT);
+ }
+ } else {
+ break;
+ }
+ } else if (r == 0) {
+ return buf_last - buf;
+ } else {
+ return WSLAY_ERR_CALLBACK_FAILURE;
+ }
+ }
+ }
+ return buf_last - buf;
+}
+
+void wslay_event_set_error(wslay_event_context_ptr ctx, int val) {
ctx->error = val;
}
-int wslay_event_want_read(wslay_event_context_ptr ctx)
-{
+int wslay_event_want_read(wslay_event_context_ptr ctx) {
return ctx->read_enabled;
}
-int wslay_event_want_write(wslay_event_context_ptr ctx)
-{
+int wslay_event_want_write(wslay_event_context_ptr ctx) {
return ctx->write_enabled &&
- (!wslay_queue_empty(ctx->send_queue) ||
- !wslay_queue_empty(ctx->send_ctrl_queue) || ctx->omsg);
+ (!wslay_queue_empty(&ctx->send_queue) ||
+ !wslay_queue_empty(&ctx->send_ctrl_queue) || ctx->omsg);
}
-void wslay_event_shutdown_read(wslay_event_context_ptr ctx)
-{
+void wslay_event_shutdown_read(wslay_event_context_ptr ctx) {
ctx->read_enabled = 0;
}
-void wslay_event_shutdown_write(wslay_event_context_ptr ctx)
-{
+void wslay_event_shutdown_write(wslay_event_context_ptr ctx) {
ctx->write_enabled = 0;
}
-int wslay_event_get_read_enabled(wslay_event_context_ptr ctx)
-{
+int wslay_event_get_read_enabled(wslay_event_context_ptr ctx) {
return ctx->read_enabled;
}
-int wslay_event_get_write_enabled(wslay_event_context_ptr ctx)
-{
+int wslay_event_get_write_enabled(wslay_event_context_ptr ctx) {
return ctx->write_enabled;
}
-int wslay_event_get_close_received(wslay_event_context_ptr ctx)
-{
+int wslay_event_get_close_received(wslay_event_context_ptr ctx) {
return (ctx->close_status & WSLAY_CLOSE_RECEIVED) > 0;
}
-int wslay_event_get_close_sent(wslay_event_context_ptr ctx)
-{
+int wslay_event_get_close_sent(wslay_event_context_ptr ctx) {
return (ctx->close_status & WSLAY_CLOSE_SENT) > 0;
}
void wslay_event_config_set_allowed_rsv_bits(wslay_event_context_ptr ctx,
- uint8_t rsv)
-{
+ uint8_t rsv) {
/* We currently only allow WSLAY_RSV1_BIT or WSLAY_RSV_NONE */
ctx->allowed_rsv_bits = rsv & WSLAY_RSV1_BIT;
}
-void wslay_event_config_set_no_buffering(wslay_event_context_ptr ctx, int val)
-{
- if(val) {
+void wslay_event_config_set_no_buffering(wslay_event_context_ptr ctx, int val) {
+ if (val) {
ctx->config |= WSLAY_CONFIG_NO_BUFFERING;
} else {
- ctx->config &= ~WSLAY_CONFIG_NO_BUFFERING;
+ ctx->config &= (uint32_t)~WSLAY_CONFIG_NO_BUFFERING;
}
}
void wslay_event_config_set_max_recv_msg_length(wslay_event_context_ptr ctx,
- uint64_t val)
-{
+ uint64_t val) {
ctx->max_recv_msg_length = val;
}
-uint16_t wslay_event_get_status_code_received(wslay_event_context_ptr ctx)
-{
+uint16_t wslay_event_get_status_code_received(wslay_event_context_ptr ctx) {
return ctx->status_code_recv;
}
-uint16_t wslay_event_get_status_code_sent(wslay_event_context_ptr ctx)
-{
+uint16_t wslay_event_get_status_code_sent(wslay_event_context_ptr ctx) {
return ctx->status_code_sent;
}
-size_t wslay_event_get_queued_msg_count(wslay_event_context_ptr ctx)
-{
+size_t wslay_event_get_queued_msg_count(wslay_event_context_ptr ctx) {
return ctx->queued_msg_count;
}
-size_t wslay_event_get_queued_msg_length(wslay_event_context_ptr ctx)
-{
+size_t wslay_event_get_queued_msg_length(wslay_event_context_ptr ctx) {
return ctx->queued_msg_length;
}
diff --git a/thirdparty/wslay/wslay_event.h b/thirdparty/wslay/wslay_event.h
index 36feb9036d..e30c3d1940 100644
--- a/thirdparty/wslay/wslay_event.h
+++ b/thirdparty/wslay/wslay_event.h
@@ -31,10 +31,10 @@
#include <wslay/wslay.h>
-struct wslay_stack;
-struct wslay_queue;
+#include "wslay_queue.h"
struct wslay_event_byte_chunk {
+ struct wslay_queue_entry qe;
uint8_t *data;
size_t data_length;
};
@@ -44,16 +44,14 @@ struct wslay_event_imsg {
uint8_t rsv;
uint8_t opcode;
uint32_t utf8state;
- struct wslay_queue *chunks;
+ struct wslay_queue chunks;
size_t msg_length;
};
-enum wslay_event_msg_type {
- WSLAY_NON_FRAGMENTED,
- WSLAY_FRAGMENTED
-};
+enum wslay_event_msg_type { WSLAY_NON_FRAGMENTED, WSLAY_FRAGMENTED };
struct wslay_event_omsg {
+ struct wslay_queue_entry qe;
uint8_t fin;
uint8_t opcode;
uint8_t rsv;
@@ -77,9 +75,7 @@ enum wslay_event_close_status {
WSLAY_CLOSE_SENT = 1 << 2
};
-enum wslay_event_config {
- WSLAY_CONFIG_NO_BUFFERING = 1 << 0
-};
+enum wslay_event_config { WSLAY_CONFIG_NO_BUFFERING = 1 << 0 };
struct wslay_event_context {
/* config status, bitwise OR of enum wslay_event_config values*/
@@ -118,9 +114,9 @@ struct wslay_event_context {
is currently sent. */
struct wslay_event_omsg *omsg;
/* Queue for non-control frames */
- struct wslay_queue/*<wslay_omsg*>*/ *send_queue;
+ struct wslay_queue /*<wslay_omsg*>*/ send_queue;
/* Queue for control frames */
- struct wslay_queue/*<wslay_omsg*>*/ *send_ctrl_queue;
+ struct wslay_queue /*<wslay_omsg*>*/ send_ctrl_queue;
/* Size of send_queue + size of send_ctrl_queue */
size_t queued_msg_count;
/* The sum of message length in send_queue */
diff --git a/thirdparty/wslay/wslay_frame.c b/thirdparty/wslay/wslay_frame.c
index 445e750ca5..435044a3f4 100644
--- a/thirdparty/wslay/wslay_frame.c
+++ b/thirdparty/wslay/wslay_frame.c
@@ -34,10 +34,9 @@
int wslay_frame_context_init(wslay_frame_context_ptr *ctx,
const struct wslay_frame_callbacks *callbacks,
- void *user_data)
-{
- *ctx = (wslay_frame_context_ptr)malloc(sizeof(struct wslay_frame_context));
- if(*ctx == NULL) {
+ void *user_data) {
+ *ctx = malloc(sizeof(struct wslay_frame_context));
+ if (*ctx == NULL) {
return -1;
}
memset(*ctx, 0, sizeof(struct wslay_frame_context));
@@ -50,38 +49,35 @@ int wslay_frame_context_init(wslay_frame_context_ptr *ctx,
return 0;
}
-void wslay_frame_context_free(wslay_frame_context_ptr ctx)
-{
- free(ctx);
-}
+void wslay_frame_context_free(wslay_frame_context_ptr ctx) { free(ctx); }
ssize_t wslay_frame_send(wslay_frame_context_ptr ctx,
- struct wslay_frame_iocb *iocb)
-{
- if(iocb->data_length > iocb->payload_length) {
+ struct wslay_frame_iocb *iocb) {
+ if (iocb->data_length > iocb->payload_length) {
return WSLAY_ERR_INVALID_ARGUMENT;
}
- if(ctx->ostate == PREP_HEADER) {
+ if (ctx->ostate == PREP_HEADER) {
uint8_t *hdptr = ctx->oheader;
memset(ctx->oheader, 0, sizeof(ctx->oheader));
- *hdptr |= (iocb->fin << 7) & 0x80u;
- *hdptr |= (iocb->rsv << 4) & 0x70u;
- *hdptr |= iocb->opcode & 0xfu;
+ *hdptr |= (uint8_t)((uint8_t)(iocb->fin << 7) & 0x80u);
+ *hdptr |= (uint8_t)((uint8_t)(iocb->rsv << 4) & 0x70u);
+ /* Suppress stubborn gcc-10 warning */
+ *hdptr |= (uint8_t)((uint8_t)(iocb->opcode << 0) & 0xfu);
++hdptr;
- *hdptr |= (iocb->mask << 7) & 0x80u;
- if(wslay_is_ctrl_frame(iocb->opcode) && iocb->payload_length > 125) {
+ *hdptr |= (uint8_t)((uint8_t)(iocb->mask << 7) & 0x80u);
+ if (wslay_is_ctrl_frame(iocb->opcode) && iocb->payload_length > 125) {
return WSLAY_ERR_INVALID_ARGUMENT;
}
- if(iocb->payload_length < 126) {
- *hdptr |= iocb->payload_length;
+ if (iocb->payload_length < 126) {
+ *hdptr |= (uint8_t)iocb->payload_length;
++hdptr;
- } else if(iocb->payload_length < (1 << 16)) {
- uint16_t len = htons(iocb->payload_length);
+ } else if (iocb->payload_length < (1 << 16)) {
+ uint16_t len = htons((uint16_t)iocb->payload_length);
*hdptr |= 126;
++hdptr;
memcpy(hdptr, &len, 2);
hdptr += 2;
- } else if(iocb->payload_length < (1ull << 63)) {
+ } else if (iocb->payload_length < (1ull << 63)) {
uint64_t len = hton64(iocb->payload_length);
*hdptr |= 127;
++hdptr;
@@ -91,9 +87,9 @@ ssize_t wslay_frame_send(wslay_frame_context_ptr ctx,
/* Too large payload length */
return WSLAY_ERR_INVALID_ARGUMENT;
}
- if(iocb->mask) {
- if(ctx->callbacks.genmask_callback(ctx->omaskkey, 4,
- ctx->user_data) != 0) {
+ if (iocb->mask) {
+ if (ctx->callbacks.genmask_callback(ctx->omaskkey, 4, ctx->user_data) !=
+ 0) {
return WSLAY_ERR_INVALID_CALLBACK;
} else {
ctx->omask = 1;
@@ -107,21 +103,21 @@ ssize_t wslay_frame_send(wslay_frame_context_ptr ctx,
ctx->opayloadlen = iocb->payload_length;
ctx->opayloadoff = 0;
}
- if(ctx->ostate == SEND_HEADER) {
- ptrdiff_t len = ctx->oheaderlimit-ctx->oheadermark;
+ if (ctx->ostate == SEND_HEADER) {
+ ptrdiff_t len = ctx->oheaderlimit - ctx->oheadermark;
ssize_t r;
int flags = 0;
- if(iocb->data_length > 0) {
+ if (iocb->data_length > 0) {
flags |= WSLAY_MSG_MORE;
};
- r = ctx->callbacks.send_callback(ctx->oheadermark, len, flags,
+ r = ctx->callbacks.send_callback(ctx->oheadermark, (size_t)len, flags,
ctx->user_data);
- if(r > 0) {
- if(r > len) {
+ if (r > 0) {
+ if (r > len) {
return WSLAY_ERR_INVALID_CALLBACK;
} else {
ctx->oheadermark += r;
- if(ctx->oheadermark == ctx->oheaderlimit) {
+ if (ctx->oheadermark == ctx->oheaderlimit) {
ctx->ostate = SEND_PAYLOAD;
} else {
return WSLAY_ERR_WANT_WRITE;
@@ -131,34 +127,34 @@ ssize_t wslay_frame_send(wslay_frame_context_ptr ctx,
return WSLAY_ERR_WANT_WRITE;
}
}
- if(ctx->ostate == SEND_PAYLOAD) {
+ if (ctx->ostate == SEND_PAYLOAD) {
size_t totallen = 0;
- if(iocb->data_length > 0) {
- if(ctx->omask) {
+ if (iocb->data_length > 0) {
+ if (ctx->omask) {
uint8_t temp[4096];
const uint8_t *datamark = iocb->data,
- *datalimit = iocb->data+iocb->data_length;
- while(datamark < datalimit) {
- size_t datalen = datalimit - datamark;
- const uint8_t *writelimit = datamark+
- wslay_min(sizeof(temp), datalen);
- size_t writelen = writelimit-datamark;
+ *datalimit = iocb->data + iocb->data_length;
+ while (datamark < datalimit) {
+ size_t datalen = (size_t)(datalimit - datamark);
+ const uint8_t *writelimit =
+ datamark + wslay_min(sizeof(temp), datalen);
+ size_t writelen = (size_t)(writelimit - datamark);
ssize_t r;
size_t i;
- for(i = 0; i < writelen; ++i) {
- temp[i] = datamark[i]^ctx->omaskkey[(ctx->opayloadoff+i)%4];
+ for (i = 0; i < writelen; ++i) {
+ temp[i] = datamark[i] ^ ctx->omaskkey[(ctx->opayloadoff + i) % 4];
}
r = ctx->callbacks.send_callback(temp, writelen, 0, ctx->user_data);
- if(r > 0) {
- if((size_t)r > writelen) {
+ if (r > 0) {
+ if ((size_t)r > writelen) {
return WSLAY_ERR_INVALID_CALLBACK;
} else {
datamark += r;
- ctx->opayloadoff += r;
- totallen += r;
+ ctx->opayloadoff += (uint64_t)r;
+ totallen += (size_t)r;
}
} else {
- if(totallen > 0) {
+ if (totallen > 0) {
break;
} else {
return WSLAY_ERR_WANT_WRITE;
@@ -169,44 +165,148 @@ ssize_t wslay_frame_send(wslay_frame_context_ptr ctx,
ssize_t r;
r = ctx->callbacks.send_callback(iocb->data, iocb->data_length, 0,
ctx->user_data);
- if(r > 0) {
- if((size_t)r > iocb->data_length) {
+ if (r > 0) {
+ if ((size_t)r > iocb->data_length) {
return WSLAY_ERR_INVALID_CALLBACK;
} else {
- ctx->opayloadoff += r;
- totallen = r;
+ ctx->opayloadoff += (uint64_t)r;
+ totallen = (size_t)r;
}
} else {
return WSLAY_ERR_WANT_WRITE;
}
}
}
- if(ctx->opayloadoff == ctx->opayloadlen) {
+ if (ctx->opayloadoff == ctx->opayloadlen) {
ctx->ostate = PREP_HEADER;
}
- return totallen;
+ return (ssize_t)totallen;
}
return WSLAY_ERR_INVALID_ARGUMENT;
}
-static void wslay_shift_ibuf(wslay_frame_context_ptr ctx)
-{
- ptrdiff_t len = ctx->ibuflimit-ctx->ibufmark;
- memmove(ctx->ibuf, ctx->ibufmark, len);
- ctx->ibuflimit = ctx->ibuf+len;
+ssize_t wslay_frame_write(wslay_frame_context_ptr ctx,
+ struct wslay_frame_iocb *iocb, uint8_t *buf,
+ size_t buflen, size_t *pwpayloadlen) {
+ uint8_t *buf_last = buf;
+ size_t i;
+ size_t hdlen;
+
+ *pwpayloadlen = 0;
+
+ if (iocb->data_length > iocb->payload_length) {
+ return WSLAY_ERR_INVALID_ARGUMENT;
+ }
+
+ switch (ctx->ostate) {
+ case PREP_HEADER:
+ case PREP_HEADER_NOBUF:
+ hdlen = 2;
+ if (iocb->payload_length < 126) {
+ /* nothing to do */
+ } else if (iocb->payload_length < (1 << 16)) {
+ hdlen += 2;
+ } else if (iocb->payload_length < (1ull << 63)) {
+ hdlen += 8;
+ }
+ if (iocb->mask) {
+ hdlen += 4;
+ }
+
+ if (buflen < hdlen) {
+ ctx->ostate = PREP_HEADER_NOBUF;
+ return 0;
+ }
+
+ memset(buf_last, 0, hdlen);
+ *buf_last |= (uint8_t)((uint8_t)(iocb->fin << 7) & 0x80u);
+ *buf_last |= (uint8_t)((uint8_t)(iocb->rsv << 4) & 0x70u);
+ /* Suppress stubborn gcc-10 warning */
+ *buf_last |= (uint8_t)((uint8_t)(iocb->opcode << 0) & 0xfu);
+ ++buf_last;
+ *buf_last |= (uint8_t)((uint8_t)(iocb->mask << 7) & 0x80u);
+ if (wslay_is_ctrl_frame(iocb->opcode) && iocb->payload_length > 125) {
+ return WSLAY_ERR_INVALID_ARGUMENT;
+ }
+ if (iocb->payload_length < 126) {
+ *buf_last |= (uint8_t)iocb->payload_length;
+ ++buf_last;
+ } else if (iocb->payload_length < (1 << 16)) {
+ uint16_t len = htons((uint16_t)iocb->payload_length);
+ *buf_last |= 126;
+ ++buf_last;
+ memcpy(buf_last, &len, 2);
+ buf_last += 2;
+ } else if (iocb->payload_length < (1ull << 63)) {
+ uint64_t len = hton64(iocb->payload_length);
+ *buf_last |= 127;
+ ++buf_last;
+ memcpy(buf_last, &len, 8);
+ buf_last += 8;
+ } else {
+ /* Too large payload length */
+ return WSLAY_ERR_INVALID_ARGUMENT;
+ }
+ if (iocb->mask) {
+ if (ctx->callbacks.genmask_callback(ctx->omaskkey, 4, ctx->user_data) !=
+ 0) {
+ return WSLAY_ERR_INVALID_CALLBACK;
+ } else {
+ ctx->omask = 1;
+ memcpy(buf_last, ctx->omaskkey, 4);
+ buf_last += 4;
+ }
+ }
+ ctx->ostate = SEND_PAYLOAD;
+ ctx->opayloadlen = iocb->payload_length;
+ ctx->opayloadoff = 0;
+
+ buflen -= (size_t)(buf_last - buf);
+ /* fall through */
+ case SEND_PAYLOAD:
+ if (iocb->data_length > 0) {
+ size_t writelen = wslay_min(buflen, iocb->data_length);
+
+ if (ctx->omask) {
+ for (i = 0; i < writelen; ++i) {
+ *buf_last++ =
+ iocb->data[i] ^ ctx->omaskkey[(ctx->opayloadoff + i) % 4];
+ }
+ } else {
+ memcpy(buf_last, iocb->data, writelen);
+ buf_last += writelen;
+ }
+
+ ctx->opayloadoff += writelen;
+ *pwpayloadlen = writelen;
+ }
+
+ if (ctx->opayloadoff == ctx->opayloadlen) {
+ ctx->ostate = PREP_HEADER;
+ }
+
+ return buf_last - buf;
+ default:
+ return WSLAY_ERR_INVALID_ARGUMENT;
+ }
+}
+
+static void wslay_shift_ibuf(wslay_frame_context_ptr ctx) {
+ ptrdiff_t len = ctx->ibuflimit - ctx->ibufmark;
+ memmove(ctx->ibuf, ctx->ibufmark, (size_t)len);
+ ctx->ibuflimit = ctx->ibuf + len;
ctx->ibufmark = ctx->ibuf;
}
-static ssize_t wslay_recv(wslay_frame_context_ptr ctx)
-{
+static ssize_t wslay_recv(wslay_frame_context_ptr ctx) {
ssize_t r;
- if(ctx->ibufmark != ctx->ibuf) {
+ if (ctx->ibufmark != ctx->ibuf) {
wslay_shift_ibuf(ctx);
}
- r = ctx->callbacks.recv_callback
- (ctx->ibuflimit, ctx->ibuf+sizeof(ctx->ibuf)-ctx->ibuflimit,
- 0, ctx->user_data);
- if(r > 0) {
+ r = ctx->callbacks.recv_callback(
+ ctx->ibuflimit, (size_t)(ctx->ibuf + sizeof(ctx->ibuf) - ctx->ibuflimit),
+ 0, ctx->user_data);
+ if (r > 0) {
ctx->ibuflimit += r;
} else {
r = WSLAY_ERR_WANT_READ;
@@ -217,17 +317,16 @@ static ssize_t wslay_recv(wslay_frame_context_ptr ctx)
#define WSLAY_AVAIL_IBUF(ctx) ((size_t)(ctx->ibuflimit - ctx->ibufmark))
ssize_t wslay_frame_recv(wslay_frame_context_ptr ctx,
- struct wslay_frame_iocb *iocb)
-{
+ struct wslay_frame_iocb *iocb) {
ssize_t r;
- if(ctx->istate == RECV_HEADER1) {
+ if (ctx->istate == RECV_HEADER1) {
uint8_t fin, opcode, rsv, payloadlen;
- if(WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
- if((r = wslay_recv(ctx)) <= 0) {
+ if (WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
+ if ((r = wslay_recv(ctx)) <= 0) {
return r;
}
}
- if(WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
+ if (WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
return WSLAY_ERR_WANT_READ;
}
fin = (ctx->ibufmark[0] >> 7) & 1;
@@ -240,19 +339,19 @@ ssize_t wslay_frame_recv(wslay_frame_context_ptr ctx,
ctx->imask = (ctx->ibufmark[0] >> 7) & 1;
payloadlen = ctx->ibufmark[0] & 0x7fu;
++ctx->ibufmark;
- if(wslay_is_ctrl_frame(opcode) && (payloadlen > 125 || !fin)) {
+ if (wslay_is_ctrl_frame(opcode) && (payloadlen > 125 || !fin)) {
return WSLAY_ERR_PROTO;
}
- if(payloadlen == 126) {
+ if (payloadlen == 126) {
ctx->istate = RECV_EXT_PAYLOADLEN;
ctx->ireqread = 2;
- } else if(payloadlen == 127) {
+ } else if (payloadlen == 127) {
ctx->istate = RECV_EXT_PAYLOADLEN;
ctx->ireqread = 8;
} else {
ctx->ipayloadlen = payloadlen;
ctx->ipayloadoff = 0;
- if(ctx->imask) {
+ if (ctx->imask) {
ctx->istate = RECV_MASKKEY;
ctx->ireqread = 4;
} else {
@@ -260,42 +359,41 @@ ssize_t wslay_frame_recv(wslay_frame_context_ptr ctx,
}
}
}
- if(ctx->istate == RECV_EXT_PAYLOADLEN) {
- if(WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
- if((r = wslay_recv(ctx)) <= 0) {
+ if (ctx->istate == RECV_EXT_PAYLOADLEN) {
+ if (WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
+ if ((r = wslay_recv(ctx)) <= 0) {
return r;
}
- if(WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
+ if (WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
return WSLAY_ERR_WANT_READ;
}
}
ctx->ipayloadlen = 0;
ctx->ipayloadoff = 0;
- memcpy((uint8_t*)&ctx->ipayloadlen+(8-ctx->ireqread),
- ctx->ibufmark, ctx->ireqread);
+ memcpy((uint8_t *)&ctx->ipayloadlen + (8 - ctx->ireqread), ctx->ibufmark,
+ ctx->ireqread);
ctx->ipayloadlen = ntoh64(ctx->ipayloadlen);
ctx->ibufmark += ctx->ireqread;
- if(ctx->ireqread == 8) {
- if(ctx->ipayloadlen < (1 << 16) ||
- ctx->ipayloadlen & (1ull << 63)) {
+ if (ctx->ireqread == 8) {
+ if (ctx->ipayloadlen < (1 << 16) || ctx->ipayloadlen & (1ull << 63)) {
return WSLAY_ERR_PROTO;
}
- } else if(ctx->ipayloadlen < 126) {
+ } else if (ctx->ipayloadlen < 126) {
return WSLAY_ERR_PROTO;
}
- if(ctx->imask) {
+ if (ctx->imask) {
ctx->istate = RECV_MASKKEY;
ctx->ireqread = 4;
} else {
ctx->istate = RECV_PAYLOAD;
}
}
- if(ctx->istate == RECV_MASKKEY) {
- if(WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
- if((r = wslay_recv(ctx)) <= 0) {
+ if (ctx->istate == RECV_MASKKEY) {
+ if (WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
+ if ((r = wslay_recv(ctx)) <= 0) {
return r;
}
- if(WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
+ if (WSLAY_AVAIL_IBUF(ctx) < ctx->ireqread) {
return WSLAY_ERR_WANT_READ;
}
}
@@ -303,25 +401,25 @@ ssize_t wslay_frame_recv(wslay_frame_context_ptr ctx,
ctx->ibufmark += 4;
ctx->istate = RECV_PAYLOAD;
}
- if(ctx->istate == RECV_PAYLOAD) {
+ if (ctx->istate == RECV_PAYLOAD) {
uint8_t *readlimit, *readmark;
- uint64_t rempayloadlen = ctx->ipayloadlen-ctx->ipayloadoff;
- if(WSLAY_AVAIL_IBUF(ctx) == 0 && rempayloadlen > 0) {
- if((r = wslay_recv(ctx)) <= 0) {
+ uint64_t rempayloadlen = ctx->ipayloadlen - ctx->ipayloadoff;
+ if (WSLAY_AVAIL_IBUF(ctx) == 0 && rempayloadlen > 0) {
+ if ((r = wslay_recv(ctx)) <= 0) {
return r;
}
}
readmark = ctx->ibufmark;
- readlimit = WSLAY_AVAIL_IBUF(ctx) < rempayloadlen ?
- ctx->ibuflimit : ctx->ibufmark+rempayloadlen;
- if(ctx->imask) {
- for(; ctx->ibufmark != readlimit;
- ++ctx->ibufmark, ++ctx->ipayloadoff) {
+ readlimit = WSLAY_AVAIL_IBUF(ctx) < rempayloadlen
+ ? ctx->ibuflimit
+ : ctx->ibufmark + rempayloadlen;
+ if (ctx->imask) {
+ for (; ctx->ibufmark != readlimit; ++ctx->ibufmark, ++ctx->ipayloadoff) {
ctx->ibufmark[0] ^= ctx->imaskkey[ctx->ipayloadoff % 4];
}
} else {
ctx->ibufmark = readlimit;
- ctx->ipayloadoff += readlimit-readmark;
+ ctx->ipayloadoff += (uint64_t)(readlimit - readmark);
}
iocb->fin = ctx->iom.fin;
iocb->rsv = ctx->iom.rsv;
@@ -329,12 +427,12 @@ ssize_t wslay_frame_recv(wslay_frame_context_ptr ctx,
iocb->payload_length = ctx->ipayloadlen;
iocb->mask = ctx->imask;
iocb->data = readmark;
- iocb->data_length = ctx->ibufmark-readmark;
- if(ctx->ipayloadlen == ctx->ipayloadoff) {
+ iocb->data_length = (size_t)(ctx->ibufmark - readmark);
+ if (ctx->ipayloadlen == ctx->ipayloadoff) {
ctx->istate = RECV_HEADER1;
ctx->ireqread = 2;
}
- return iocb->data_length;
+ return (ssize_t)iocb->data_length;
}
return WSLAY_ERR_INVALID_ARGUMENT;
}
diff --git a/thirdparty/wslay/wslay_frame.h b/thirdparty/wslay/wslay_frame.h
index 6a75858cc7..3ac98112b5 100644
--- a/thirdparty/wslay/wslay_frame.h
+++ b/thirdparty/wslay/wslay_frame.h
@@ -33,6 +33,7 @@
enum wslay_frame_state {
PREP_HEADER,
+ PREP_HEADER_NOBUF,
SEND_HEADER,
SEND_PAYLOAD,
RECV_HEADER1,
diff --git a/thirdparty/wslay/wslay_stack.h b/thirdparty/wslay/wslay_macro.h
index 16e4e968eb..a06cff98e1 100644
--- a/thirdparty/wslay/wslay_stack.h
+++ b/thirdparty/wslay/wslay_macro.h
@@ -1,7 +1,7 @@
/*
* Wslay - The WebSocket Library
*
- * Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
+ * Copyright (c) 2020 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -22,8 +22,8 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#ifndef WSLAY_STACK_H
-#define WSLAY_STACK_H
+#ifndef WSLAY_MACRO_H
+#define WSLAY_MACRO_H
#ifdef HAVE_CONFIG_H
# include "config.h"
@@ -31,20 +31,9 @@
#include <wslay/wslay.h>
-struct wslay_stack_cell {
- void *data;
- struct wslay_stack_cell *next;
-};
+#include <stddef.h>
-struct wslay_stack {
- struct wslay_stack_cell *top;
-};
+#define wslay_struct_of(ptr, type, member) \
+ ((type *)(void *)((char *)(ptr)-offsetof(type, member)))
-struct wslay_stack* wslay_stack_new();
-void wslay_stack_free(struct wslay_stack *stack);
-int wslay_stack_push(struct wslay_stack *stack, void *data);
-void wslay_stack_pop(struct wslay_stack *stack);
-void* wslay_stack_top(struct wslay_stack *stack);
-int wslay_stack_empty(struct wslay_stack *stack);
-
-#endif /* WSLAY_STACK_H */
+#endif /* WSLAY_MACRO_H */
diff --git a/thirdparty/wslay/wslay_net.c b/thirdparty/wslay/wslay_net.c
index d3867c21fb..e256158b4c 100644
--- a/thirdparty/wslay/wslay_net.c
+++ b/thirdparty/wslay/wslay_net.c
@@ -26,10 +26,9 @@
#ifndef WORDS_BIGENDIAN
-uint64_t wslay_byteswap64(uint64_t x)
-{
+uint64_t wslay_byteswap64(uint64_t x) {
uint64_t u = ntohl(x & 0xffffffffllu);
- uint64_t l = ntohl(x >> 32);
+ uint64_t l = ntohl((uint32_t)(x >> 32));
return (u << 32) | l;
}
diff --git a/thirdparty/wslay/wslay_queue.c b/thirdparty/wslay/wslay_queue.c
index 8d2669687d..ebde3ba83d 100644
--- a/thirdparty/wslay/wslay_queue.c
+++ b/thirdparty/wslay/wslay_queue.c
@@ -27,91 +27,51 @@
#include <string.h>
#include <assert.h>
-struct wslay_queue* wslay_queue_new(void)
-{
- struct wslay_queue *queue = (struct wslay_queue*)malloc
- (sizeof(struct wslay_queue));
- if(!queue) {
- return NULL;
- }
- queue->top = queue->tail = NULL;
- return queue;
-}
+#include "wslay_macro.h"
-void wslay_queue_free(struct wslay_queue *queue)
-{
- if(!queue) {
- return;
- } else {
- struct wslay_queue_cell *p = queue->top;
- while(p) {
- struct wslay_queue_cell *next = p->next;
- free(p);
- p = next;
- }
- free(queue);
- }
+void wslay_queue_init(struct wslay_queue *queue) {
+ queue->top = NULL;
+ queue->tail = &queue->top;
}
-int wslay_queue_push(struct wslay_queue *queue, void *data)
-{
- struct wslay_queue_cell *new_cell = (struct wslay_queue_cell*)malloc
- (sizeof(struct wslay_queue_cell));
- if(!new_cell) {
- return WSLAY_ERR_NOMEM;
- }
- new_cell->data = data;
- new_cell->next = NULL;
- if(queue->tail) {
- queue->tail->next = new_cell;
- queue->tail = new_cell;
+void wslay_queue_deinit(struct wslay_queue *queue) { (void)queue; }
- } else {
- queue->top = queue->tail = new_cell;
- }
- return 0;
+void wslay_queue_push(struct wslay_queue *queue,
+ struct wslay_queue_entry *ent) {
+ ent->next = NULL;
+ *queue->tail = ent;
+ queue->tail = &ent->next;
}
-int wslay_queue_push_front(struct wslay_queue *queue, void *data)
-{
- struct wslay_queue_cell *new_cell = (struct wslay_queue_cell*)malloc
- (sizeof(struct wslay_queue_cell));
- if(!new_cell) {
- return WSLAY_ERR_NOMEM;
- }
- new_cell->data = data;
- new_cell->next = queue->top;
- queue->top = new_cell;
- if(!queue->tail) {
- queue->tail = queue->top;
+void wslay_queue_push_front(struct wslay_queue *queue,
+ struct wslay_queue_entry *ent) {
+ ent->next = queue->top;
+ queue->top = ent;
+
+ if (ent->next == NULL) {
+ queue->tail = &ent->next;
}
- return 0;
}
-void wslay_queue_pop(struct wslay_queue *queue)
-{
- struct wslay_queue_cell *top = queue->top;
- assert(top);
- queue->top = top->next;
- if(top == queue->tail) {
- queue->tail = NULL;
+void wslay_queue_pop(struct wslay_queue *queue) {
+ assert(queue->top);
+ queue->top = queue->top->next;
+ if (queue->top == NULL) {
+ queue->tail = &queue->top;
}
- free(top);
}
-void* wslay_queue_top(struct wslay_queue *queue)
-{
+struct wslay_queue_entry *wslay_queue_top(struct wslay_queue *queue) {
assert(queue->top);
- return queue->top->data;
+ return queue->top;
}
-void* wslay_queue_tail(struct wslay_queue *queue)
-{
- assert(queue->tail);
- return queue->tail->data;
+struct wslay_queue_entry *wslay_queue_tail(struct wslay_queue *queue) {
+ assert(queue->top);
+ return wslay_struct_of(queue->tail, struct wslay_queue_entry, next);
}
-int wslay_queue_empty(struct wslay_queue *queue)
-{
+int wslay_queue_empty(struct wslay_queue *queue) {
+ assert(queue->top || queue->tail == &queue->top);
return queue->top == NULL;
}
diff --git a/thirdparty/wslay/wslay_queue.h b/thirdparty/wslay/wslay_queue.h
index 55e78a042e..fa16aea489 100644
--- a/thirdparty/wslay/wslay_queue.h
+++ b/thirdparty/wslay/wslay_queue.h
@@ -31,23 +31,23 @@
#include <wslay/wslay.h>
-struct wslay_queue_cell {
- void *data;
- struct wslay_queue_cell *next;
+struct wslay_queue_entry {
+ struct wslay_queue_entry *next;
};
struct wslay_queue {
- struct wslay_queue_cell *top;
- struct wslay_queue_cell *tail;
+ struct wslay_queue_entry *top;
+ struct wslay_queue_entry **tail;
};
-struct wslay_queue* wslay_queue_new(void);
-void wslay_queue_free(struct wslay_queue *queue);
-int wslay_queue_push(struct wslay_queue *queue, void *data);
-int wslay_queue_push_front(struct wslay_queue *queue, void *data);
+void wslay_queue_init(struct wslay_queue *queue);
+void wslay_queue_deinit(struct wslay_queue *queue);
+void wslay_queue_push(struct wslay_queue *queue, struct wslay_queue_entry *ent);
+void wslay_queue_push_front(struct wslay_queue *queue,
+ struct wslay_queue_entry *ent);
void wslay_queue_pop(struct wslay_queue *queue);
-void* wslay_queue_top(struct wslay_queue *queue);
-void* wslay_queue_tail(struct wslay_queue *queue);
+struct wslay_queue_entry *wslay_queue_top(struct wslay_queue *queue);
+struct wslay_queue_entry *wslay_queue_tail(struct wslay_queue *queue);
int wslay_queue_empty(struct wslay_queue *queue);
#endif /* WSLAY_QUEUE_H */
diff --git a/thirdparty/wslay/wslay_stack.c b/thirdparty/wslay/wslay_stack.c
deleted file mode 100644
index 0e05d74031..0000000000
--- a/thirdparty/wslay/wslay_stack.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Wslay - The WebSocket Library
- *
- * Copyright (c) 2011, 2012 Tatsuhiro Tsujikawa
- *
- * 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.
- */
-#include "wslay_stack.h"
-
-#include <string.h>
-#include <assert.h>
-
-struct wslay_stack* wslay_stack_new()
-{
- struct wslay_stack *stack = (struct wslay_stack*)malloc
- (sizeof(struct wslay_stack));
- if(!stack) {
- return NULL;
- }
- stack->top = NULL;
- return stack;
-}
-
-void wslay_stack_free(struct wslay_stack *stack)
-{
- struct wslay_stack_cell *p;
- if(!stack) {
- return;
- }
- p = stack->top;
- while(p) {
- struct wslay_stack_cell *next = p->next;
- free(p);
- p = next;
- }
- free(stack);
-}
-
-int wslay_stack_push(struct wslay_stack *stack, void *data)
-{
- struct wslay_stack_cell *new_cell = (struct wslay_stack_cell*)malloc
- (sizeof(struct wslay_stack_cell));
- if(!new_cell) {
- return WSLAY_ERR_NOMEM;
- }
- new_cell->data = data;
- new_cell->next = stack->top;
- stack->top = new_cell;
- return 0;
-}
-
-void wslay_stack_pop(struct wslay_stack *stack)
-{
- struct wslay_stack_cell *top = stack->top;
- assert(top);
- stack->top = top->next;
- free(top);
-}
-
-void* wslay_stack_top(struct wslay_stack *stack)
-{
- assert(stack->top);
- return stack->top->data;
-}
-
-int wslay_stack_empty(struct wslay_stack *stack)
-{
- return stack->top == NULL;
-}
diff --git a/thirdparty/xatlas/xatlas.cpp b/thirdparty/xatlas/xatlas.cpp
index 9f66ae0067..d92ef1a83a 100644
--- a/thirdparty/xatlas/xatlas.cpp
+++ b/thirdparty/xatlas/xatlas.cpp
@@ -40,14 +40,14 @@ Copyright (c) 2012 Brandon Pelfrey
#if XATLAS_C_API
#include "xatlas_c.h"
#endif
-#include <assert.h>
-#include <float.h> // FLT_MAX
-#include <limits.h>
-#include <math.h>
#include <atomic>
#include <condition_variable>
#include <mutex>
#include <thread>
+#include <assert.h>
+#include <float.h> // FLT_MAX
+#include <limits.h>
+#include <math.h>
#define __STDC_LIMIT_MACROS
#include <stdint.h>
#include <stdio.h>
@@ -76,10 +76,7 @@ Copyright (c) 2012 Brandon Pelfrey
#define XA_XSTR(x) XA_STR(x)
#ifndef XA_ASSERT
-#define XA_ASSERT(exp) \
- if (!(exp)) { \
- XA_PRINT_WARNING("\rASSERT: %s %s %d\n", XA_XSTR(exp), __FILE__, __LINE__); \
- }
+#define XA_ASSERT(exp) if (!(exp)) { XA_PRINT_WARNING("\rASSERT: %s %s %d\n", XA_XSTR(exp), __FILE__, __LINE__); }
#endif
#ifndef XA_DEBUG_ASSERT
@@ -87,13 +84,13 @@ Copyright (c) 2012 Brandon Pelfrey
#endif
#ifndef XA_PRINT
-#define XA_PRINT(...) \
+#define XA_PRINT(...) \
if (xatlas::internal::s_print && xatlas::internal::s_printVerbose) \
xatlas::internal::s_print(__VA_ARGS__);
#endif
#ifndef XA_PRINT_WARNING
-#define XA_PRINT_WARNING(...) \
+#define XA_PRINT_WARNING(...) \
if (xatlas::internal::s_print) \
xatlas::internal::s_print(__VA_ARGS__);
#endif
@@ -145,14 +142,18 @@ Copyright (c) 2012 Brandon Pelfrey
#define XA_DEBUG_EXPORT_OBJ_INVALID_PARAMETERIZATION 0
#define XA_DEBUG_EXPORT_OBJ_RECOMPUTED_CHARTS 0
-#define XA_DEBUG_EXPORT_OBJ (0 || XA_DEBUG_EXPORT_OBJ_FACE_GROUPS || XA_DEBUG_EXPORT_OBJ_CHART_GROUPS || XA_DEBUG_EXPORT_OBJ_PLANAR_REGIONS || XA_DEBUG_EXPORT_OBJ_CHARTS || XA_DEBUG_EXPORT_OBJ_TJUNCTION || XA_DEBUG_EXPORT_OBJ_CHARTS_AFTER_PARAMETERIZATION || XA_DEBUG_EXPORT_OBJ_INVALID_PARAMETERIZATION || XA_DEBUG_EXPORT_OBJ_RECOMPUTED_CHARTS)
+#define XA_DEBUG_EXPORT_OBJ (0 \
+ || XA_DEBUG_EXPORT_OBJ_FACE_GROUPS \
+ || XA_DEBUG_EXPORT_OBJ_CHART_GROUPS \
+ || XA_DEBUG_EXPORT_OBJ_PLANAR_REGIONS \
+ || XA_DEBUG_EXPORT_OBJ_CHARTS \
+ || XA_DEBUG_EXPORT_OBJ_TJUNCTION \
+ || XA_DEBUG_EXPORT_OBJ_CHARTS_AFTER_PARAMETERIZATION \
+ || XA_DEBUG_EXPORT_OBJ_INVALID_PARAMETERIZATION \
+ || XA_DEBUG_EXPORT_OBJ_RECOMPUTED_CHARTS)
#ifdef _MSC_VER
-#define XA_FOPEN(_file, _filename, _mode) \
- { \
- if (fopen_s(&_file, _filename, _mode) != 0) \
- _file = NULL; \
- }
+#define XA_FOPEN(_file, _filename, _mode) { if (fopen_s(&_file, _filename, _mode) != 0) _file = NULL; }
#define XA_SPRINTF(_buffer, _size, _format, ...) sprintf_s(_buffer, _size, _format, __VA_ARGS__)
#else
#define XA_FOPEN(_file, _filename, _mode) _file = fopen(_filename, _mode)
@@ -172,12 +173,11 @@ typedef uint64_t Duration;
#define XA_PROFILE_START(var) const std::chrono::time_point<std::chrono::high_resolution_clock> var##Start = std::chrono::high_resolution_clock::now();
#define XA_PROFILE_END(var) internal::s_profile.var += uint64_t(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - var##Start).count());
-#define XA_PROFILE_PRINT_AND_RESET(label, var) \
- XA_PRINT("%s%.2f seconds (%g ms)\n", label, internal::durationToSeconds(internal::s_profile.var), internal::durationToMs(internal::s_profile.var)); \
- internal::s_profile.var = 0u;
+#define XA_PROFILE_PRINT_AND_RESET(label, var) XA_PRINT("%s%.2f seconds (%g ms)\n", label, internal::durationToSeconds(internal::s_profile.var), internal::durationToMs(internal::s_profile.var)); internal::s_profile.var = 0u;
#define XA_PROFILE_ALLOC 0
-struct ProfileData {
+struct ProfileData
+{
#if XA_PROFILE_ALLOC
std::atomic<Duration> alloc;
#endif
@@ -232,11 +232,13 @@ struct ProfileData {
static ProfileData s_profile;
-static double durationToMs(Duration c) {
+static double durationToMs(Duration c)
+{
return (double)c * 0.001;
}
-static double durationToSeconds(Duration c) {
+static double durationToSeconds(Duration c)
+{
return (double)c * 0.000001;
}
#else
@@ -246,8 +248,10 @@ static double durationToSeconds(Duration c) {
#define XA_PROFILE_ALLOC 0
#endif
-struct MemTag {
- enum {
+struct MemTag
+{
+ enum
+ {
Default,
BitImage,
BVH,
@@ -270,7 +274,8 @@ struct MemTag {
};
#if XA_DEBUG_HEAP
-struct AllocHeader {
+struct AllocHeader
+{
size_t size;
const char *file;
int line;
@@ -283,10 +288,11 @@ struct AllocHeader {
static std::mutex s_allocMutex;
static AllocHeader *s_allocRoot = nullptr;
static size_t s_allocTotalCount = 0, s_allocTotalSize = 0, s_allocPeakSize = 0, s_allocCount[MemTag::Count] = { 0 }, s_allocTotalTagSize[MemTag::Count] = { 0 }, s_allocPeakTagSize[MemTag::Count] = { 0 };
-static uint32_t s_allocId = 0;
+static uint32_t s_allocId =0 ;
static constexpr uint32_t kAllocRedzone = 0x12345678;
-static void *Realloc(void *ptr, size_t size, int tag, const char *file, int line) {
+static void *Realloc(void *ptr, size_t size, int tag, const char *file, int line)
+{
std::unique_lock<std::mutex> lock(s_allocMutex);
if (!size && !ptr)
return nullptr;
@@ -347,7 +353,8 @@ static void *Realloc(void *ptr, size_t size, int tag, const char *file, int line
return newPtr + sizeof(AllocHeader);
}
-static void ReportLeaks() {
+static void ReportLeaks()
+{
printf("Checking for memory leaks...\n");
bool anyLeaks = false;
AllocHeader *header = s_allocRoot;
@@ -375,7 +382,8 @@ static void ReportLeaks() {
s_allocTotalTagSize[i] = s_allocPeakTagSize[i] = 0;
}
-static void PrintMemoryUsage() {
+static void PrintMemoryUsage()
+{
XA_PRINT("Total allocations: %zu\n", s_allocTotalCount);
XA_PRINT("Memory usage: %0.2fMB current, %0.2fMB peak\n", internal::s_allocTotalSize / 1024.0f / 1024.0f, internal::s_allocPeakSize / 1024.0f / 1024.0f);
static const char *labels[] = { // Sync with MemTag
@@ -404,7 +412,8 @@ static void PrintMemoryUsage() {
#define XA_PRINT_MEM_USAGE internal::PrintMemoryUsage();
#else
-static void *Realloc(void *ptr, size_t size, int /*tag*/, const char * /*file*/, int /*line*/) {
+static void *Realloc(void *ptr, size_t size, int /*tag*/, const char * /*file*/, int /*line*/)
+{
if (size == 0 && !ptr)
return nullptr;
if (size == 0 && s_free) {
@@ -430,75 +439,89 @@ static constexpr float kEpsilon = 0.0001f;
static constexpr float kAreaEpsilon = FLT_EPSILON;
static constexpr float kNormalEpsilon = 0.001f;
-static int align(int x, int a) {
+static int align(int x, int a)
+{
return (x + a - 1) & ~(a - 1);
}
template <typename T>
-static T max(const T &a, const T &b) {
+static T max(const T &a, const T &b)
+{
return a > b ? a : b;
}
template <typename T>
-static T min(const T &a, const T &b) {
+static T min(const T &a, const T &b)
+{
return a < b ? a : b;
}
template <typename T>
-static T max3(const T &a, const T &b, const T &c) {
+static T max3(const T &a, const T &b, const T &c)
+{
return max(a, max(b, c));
}
/// Return the maximum of the three arguments.
template <typename T>
-static T min3(const T &a, const T &b, const T &c) {
+static T min3(const T &a, const T &b, const T &c)
+{
return min(a, min(b, c));
}
/// Clamp between two values.
template <typename T>
-static T clamp(const T &x, const T &a, const T &b) {
+static T clamp(const T &x, const T &a, const T &b)
+{
return min(max(x, a), b);
}
template <typename T>
-static void swap(T &a, T &b) {
+static void swap(T &a, T &b)
+{
T temp = a;
a = b;
b = temp;
}
-union FloatUint32 {
+union FloatUint32
+{
float f;
uint32_t u;
};
-static bool isFinite(float f) {
+static bool isFinite(float f)
+{
FloatUint32 fu;
fu.f = f;
return fu.u != 0x7F800000u && fu.u != 0x7F800001u;
}
-static bool isNan(float f) {
+static bool isNan(float f)
+{
return f != f;
}
// Robust floating point comparisons:
// http://realtimecollisiondetection.net/blog/?p=89
-static bool equal(const float f0, const float f1, const float epsilon) {
+static bool equal(const float f0, const float f1, const float epsilon)
+{
//return fabs(f0-f1) <= epsilon;
return fabs(f0 - f1) <= epsilon * max3(1.0f, fabsf(f0), fabsf(f1));
}
-static int ftoi_ceil(float val) {
+static int ftoi_ceil(float val)
+{
return (int)ceilf(val);
}
-static bool isZero(const float f, const float epsilon) {
+static bool isZero(const float f, const float epsilon)
+{
return fabs(f) <= epsilon;
}
-static float square(float f) {
+static float square(float f)
+{
return f * f;
}
@@ -508,8 +531,9 @@ static float square(float f) {
* @note isPowerOfTwo(x) == true -> nextPowerOfTwo(x) == x
* @note nextPowerOfTwo(x) = 2 << log2(x-1)
*/
-static uint32_t nextPowerOfTwo(uint32_t x) {
- XA_DEBUG_ASSERT(x != 0);
+static uint32_t nextPowerOfTwo(uint32_t x)
+{
+ XA_DEBUG_ASSERT( x != 0 );
// On modern CPUs this is supposed to be as fast as using the bsr instruction.
x--;
x |= x >> 1;
@@ -520,34 +544,38 @@ static uint32_t nextPowerOfTwo(uint32_t x) {
return x + 1;
}
-class Vector2 {
+class Vector2
+{
public:
Vector2() {}
- explicit Vector2(float f) :
- x(f), y(f) {}
- Vector2(float _x, float _y) :
- x(_x), y(_y) {}
+ explicit Vector2(float f) : x(f), y(f) {}
+ Vector2(float _x, float _y): x(_x), y(_y) {}
- Vector2 operator-() const {
+ Vector2 operator-() const
+ {
return Vector2(-x, -y);
}
- void operator+=(const Vector2 &v) {
+ void operator+=(const Vector2 &v)
+ {
x += v.x;
y += v.y;
}
- void operator-=(const Vector2 &v) {
+ void operator-=(const Vector2 &v)
+ {
x -= v.x;
y -= v.y;
}
- void operator*=(float s) {
+ void operator*=(float s)
+ {
x *= s;
y *= s;
}
- void operator*=(const Vector2 &v) {
+ void operator*=(const Vector2 &v)
+ {
x *= v.x;
y *= v.y;
}
@@ -555,11 +583,13 @@ public:
float x, y;
};
-static bool operator==(const Vector2 &a, const Vector2 &b) {
+static bool operator==(const Vector2 &a, const Vector2 &b)
+{
return a.x == b.x && a.y == b.y;
}
-static bool operator!=(const Vector2 &a, const Vector2 &b) {
+static bool operator!=(const Vector2 &a, const Vector2 &b)
+{
return a.x != b.x || a.y != b.y;
}
@@ -568,33 +598,40 @@ static bool operator!=(const Vector2 &a, const Vector2 &b) {
return Vector2(a.x + b.x, a.y + b.y);
}*/
-static Vector2 operator-(const Vector2 &a, const Vector2 &b) {
+static Vector2 operator-(const Vector2 &a, const Vector2 &b)
+{
return Vector2(a.x - b.x, a.y - b.y);
}
-static Vector2 operator*(const Vector2 &v, float s) {
+static Vector2 operator*(const Vector2 &v, float s)
+{
return Vector2(v.x * s, v.y * s);
}
-static float dot(const Vector2 &a, const Vector2 &b) {
+static float dot(const Vector2 &a, const Vector2 &b)
+{
return a.x * b.x + a.y * b.y;
}
-static float lengthSquared(const Vector2 &v) {
+static float lengthSquared(const Vector2 &v)
+{
return v.x * v.x + v.y * v.y;
}
-static float length(const Vector2 &v) {
+static float length(const Vector2 &v)
+{
return sqrtf(lengthSquared(v));
}
#if XA_DEBUG
-static bool isNormalized(const Vector2 &v, float epsilon = kNormalEpsilon) {
+static bool isNormalized(const Vector2 &v, float epsilon = kNormalEpsilon)
+{
return equal(length(v), 1, epsilon);
}
#endif
-static Vector2 normalize(const Vector2 &v) {
+static Vector2 normalize(const Vector2 &v)
+{
const float l = length(v);
XA_DEBUG_ASSERT(l > 0.0f); // Never negative.
const Vector2 n = v * (1.0f / l);
@@ -602,30 +639,36 @@ static Vector2 normalize(const Vector2 &v) {
return n;
}
-static Vector2 normalizeSafe(const Vector2 &v, const Vector2 &fallback) {
+static Vector2 normalizeSafe(const Vector2 &v, const Vector2 &fallback)
+{
const float l = length(v);
if (l > 0.0f) // Never negative.
return v * (1.0f / l);
return fallback;
}
-static bool equal(const Vector2 &v1, const Vector2 &v2, float epsilon) {
+static bool equal(const Vector2 &v1, const Vector2 &v2, float epsilon)
+{
return equal(v1.x, v2.x, epsilon) && equal(v1.y, v2.y, epsilon);
}
-static Vector2 min(const Vector2 &a, const Vector2 &b) {
+static Vector2 min(const Vector2 &a, const Vector2 &b)
+{
return Vector2(min(a.x, b.x), min(a.y, b.y));
}
-static Vector2 max(const Vector2 &a, const Vector2 &b) {
+static Vector2 max(const Vector2 &a, const Vector2 &b)
+{
return Vector2(max(a.x, b.x), max(a.y, b.y));
}
-static bool isFinite(const Vector2 &v) {
+static bool isFinite(const Vector2 &v)
+{
return isFinite(v.x) && isFinite(v.y);
}
-static float triangleArea(const Vector2 &a, const Vector2 &b, const Vector2 &c) {
+static float triangleArea(const Vector2 &a, const Vector2 &b, const Vector2 &c)
+{
// IC: While it may be appealing to use the following expression:
//return (c.x * a.y + a.x * b.y + b.x * c.y - b.x * a.y - c.x * b.y - a.x * c.y) * 0.5f;
// That's actually a terrible idea. Small triangles far from the origin can end up producing fairly large floating point
@@ -639,7 +682,8 @@ static float triangleArea(const Vector2 &a, const Vector2 &b, const Vector2 &c)
return (v0.x * v1.y - v0.y * v1.x) * 0.5f;
}
-static bool linesIntersect(const Vector2 &a1, const Vector2 &a2, const Vector2 &b1, const Vector2 &b2, float epsilon) {
+static bool linesIntersect(const Vector2 &a1, const Vector2 &a2, const Vector2 &b1, const Vector2 &b2, float epsilon)
+{
const Vector2 v0 = a2 - a1;
const Vector2 v1 = b2 - b1;
const float denom = -v1.x * v0.y + v0.x * v1.y;
@@ -647,70 +691,76 @@ static bool linesIntersect(const Vector2 &a1, const Vector2 &a2, const Vector2 &
return false;
const float s = (-v0.y * (a1.x - b1.x) + v0.x * (a1.y - b1.y)) / denom;
if (s > epsilon && s < 1.0f - epsilon) {
- const float t = (v1.x * (a1.y - b1.y) - v1.y * (a1.x - b1.x)) / denom;
+ const float t = ( v1.x * (a1.y - b1.y) - v1.y * (a1.x - b1.x)) / denom;
return t > epsilon && t < 1.0f - epsilon;
}
return false;
}
-struct Vector2i {
+struct Vector2i
+{
Vector2i() {}
- Vector2i(int32_t _x, int32_t _y) :
- x(_x), y(_y) {}
+ Vector2i(int32_t _x, int32_t _y) : x(_x), y(_y) {}
int32_t x, y;
};
-class Vector3 {
+class Vector3
+{
public:
Vector3() {}
- explicit Vector3(float f) :
- x(f), y(f), z(f) {}
- Vector3(float _x, float _y, float _z) :
- x(_x), y(_y), z(_z) {}
- Vector3(const Vector2 &v, float _z) :
- x(v.x), y(v.y), z(_z) {}
-
- Vector2 xy() const {
+ explicit Vector3(float f) : x(f), y(f), z(f) {}
+ Vector3(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {}
+ Vector3(const Vector2 &v, float _z) : x(v.x), y(v.y), z(_z) {}
+
+ Vector2 xy() const
+ {
return Vector2(x, y);
}
- Vector3 operator-() const {
+ Vector3 operator-() const
+ {
return Vector3(-x, -y, -z);
}
- void operator+=(const Vector3 &v) {
+ void operator+=(const Vector3 &v)
+ {
x += v.x;
y += v.y;
z += v.z;
}
- void operator-=(const Vector3 &v) {
+ void operator-=(const Vector3 &v)
+ {
x -= v.x;
y -= v.y;
z -= v.z;
}
- void operator*=(float s) {
+ void operator*=(float s)
+ {
x *= s;
y *= s;
z *= s;
}
- void operator/=(float s) {
+ void operator/=(float s)
+ {
float is = 1.0f / s;
x *= is;
y *= is;
z *= is;
}
- void operator*=(const Vector3 &v) {
+ void operator*=(const Vector3 &v)
+ {
x *= v.x;
y *= v.y;
z *= v.z;
}
- void operator/=(const Vector3 &v) {
+ void operator/=(const Vector3 &v)
+ {
x /= v.x;
y /= v.y;
z /= v.z;
@@ -719,47 +769,58 @@ public:
float x, y, z;
};
-static Vector3 operator+(const Vector3 &a, const Vector3 &b) {
+static Vector3 operator+(const Vector3 &a, const Vector3 &b)
+{
return Vector3(a.x + b.x, a.y + b.y, a.z + b.z);
}
-static Vector3 operator-(const Vector3 &a, const Vector3 &b) {
+static Vector3 operator-(const Vector3 &a, const Vector3 &b)
+{
return Vector3(a.x - b.x, a.y - b.y, a.z - b.z);
}
-static bool operator==(const Vector3 &a, const Vector3 &b) {
+static bool operator==(const Vector3 &a, const Vector3 &b)
+{
return a.x == b.x && a.y == b.y && a.z == b.z;
}
-static Vector3 cross(const Vector3 &a, const Vector3 &b) {
+static Vector3 cross(const Vector3 &a, const Vector3 &b)
+{
return Vector3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);
}
-static Vector3 operator*(const Vector3 &v, float s) {
+static Vector3 operator*(const Vector3 &v, float s)
+{
return Vector3(v.x * s, v.y * s, v.z * s);
}
-static Vector3 operator/(const Vector3 &v, float s) {
+static Vector3 operator/(const Vector3 &v, float s)
+{
return v * (1.0f / s);
}
-static float dot(const Vector3 &a, const Vector3 &b) {
+static float dot(const Vector3 &a, const Vector3 &b)
+{
return a.x * b.x + a.y * b.y + a.z * b.z;
}
-static float lengthSquared(const Vector3 &v) {
+static float lengthSquared(const Vector3 &v)
+{
return v.x * v.x + v.y * v.y + v.z * v.z;
}
-static float length(const Vector3 &v) {
+static float length(const Vector3 &v)
+{
return sqrtf(lengthSquared(v));
}
-static bool isNormalized(const Vector3 &v, float epsilon = kNormalEpsilon) {
+static bool isNormalized(const Vector3 &v, float epsilon = kNormalEpsilon)
+{
return equal(length(v), 1.0f, epsilon);
}
-static Vector3 normalize(const Vector3 &v) {
+static Vector3 normalize(const Vector3 &v)
+{
const float l = length(v);
XA_DEBUG_ASSERT(l > 0.0f); // Never negative.
const Vector3 n = v * (1.0f / l);
@@ -767,103 +828,116 @@ static Vector3 normalize(const Vector3 &v) {
return n;
}
-static Vector3 normalizeSafe(const Vector3 &v, const Vector3 &fallback) {
+static Vector3 normalizeSafe(const Vector3 &v, const Vector3 &fallback)
+{
const float l = length(v);
if (l > 0.0f) // Never negative.
return v * (1.0f / l);
return fallback;
}
-static bool equal(const Vector3 &v0, const Vector3 &v1, float epsilon) {
+static bool equal(const Vector3 &v0, const Vector3 &v1, float epsilon)
+{
return fabs(v0.x - v1.x) <= epsilon && fabs(v0.y - v1.y) <= epsilon && fabs(v0.z - v1.z) <= epsilon;
}
-static Vector3 min(const Vector3 &a, const Vector3 &b) {
+static Vector3 min(const Vector3 &a, const Vector3 &b)
+{
return Vector3(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z));
}
-static Vector3 max(const Vector3 &a, const Vector3 &b) {
+static Vector3 max(const Vector3 &a, const Vector3 &b)
+{
return Vector3(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z));
}
#if XA_DEBUG
-bool isFinite(const Vector3 &v) {
+bool isFinite(const Vector3 &v)
+{
return isFinite(v.x) && isFinite(v.y) && isFinite(v.z);
}
#endif
-struct Extents2 {
+struct Extents2
+{
Vector2 min, max;
Extents2() {}
- Extents2(Vector2 p1, Vector2 p2) {
+ Extents2(Vector2 p1, Vector2 p2)
+ {
min = xatlas::internal::min(p1, p2);
max = xatlas::internal::max(p1, p2);
}
- void reset() {
+ void reset()
+ {
min.x = min.y = FLT_MAX;
max.x = max.y = -FLT_MAX;
}
- void add(Vector2 p) {
+ void add(Vector2 p)
+ {
min = xatlas::internal::min(min, p);
max = xatlas::internal::max(max, p);
}
- Vector2 midpoint() const {
+ Vector2 midpoint() const
+ {
return Vector2(min.x + (max.x - min.x) * 0.5f, min.y + (max.y - min.y) * 0.5f);
}
- static bool intersect(const Extents2 &e1, const Extents2 &e2) {
+ static bool intersect(const Extents2 &e1, const Extents2 &e2)
+ {
return e1.min.x <= e2.max.x && e1.max.x >= e2.min.x && e1.min.y <= e2.max.y && e1.max.y >= e2.min.y;
}
};
// From Fast-BVH
-struct AABB {
- AABB() :
- min(FLT_MAX, FLT_MAX, FLT_MAX), max(-FLT_MAX, -FLT_MAX, -FLT_MAX) {}
- AABB(const Vector3 &_min, const Vector3 &_max) :
- min(_min), max(_max) {}
- AABB(const Vector3 &p, float radius = 0.0f) :
- min(p), max(p) {
- if (radius > 0.0f)
- expand(radius);
- }
-
- bool intersect(const AABB &other) const {
+struct AABB
+{
+ AABB() : min(FLT_MAX, FLT_MAX, FLT_MAX), max(-FLT_MAX, -FLT_MAX, -FLT_MAX) {}
+ AABB(const Vector3 &_min, const Vector3 &_max) : min(_min), max(_max) { }
+ AABB(const Vector3 &p, float radius = 0.0f) : min(p), max(p) { if (radius > 0.0f) expand(radius); }
+
+ bool intersect(const AABB &other) const
+ {
return min.x <= other.max.x && max.x >= other.min.x && min.y <= other.max.y && max.y >= other.min.y && min.z <= other.max.z && max.z >= other.min.z;
}
- void expandToInclude(const Vector3 &p) {
+ void expandToInclude(const Vector3 &p)
+ {
min = internal::min(min, p);
max = internal::max(max, p);
}
- void expandToInclude(const AABB &aabb) {
+ void expandToInclude(const AABB &aabb)
+ {
min = internal::min(min, aabb.min);
max = internal::max(max, aabb.max);
}
- void expand(float amount) {
+ void expand(float amount)
+ {
min -= Vector3(amount);
max += Vector3(amount);
}
- Vector3 centroid() const {
+ Vector3 centroid() const
+ {
return min + (max - min) * 0.5f;
}
- uint32_t maxDimension() const {
+ uint32_t maxDimension() const
+ {
const Vector3 extent = max - min;
uint32_t result = 0;
if (extent.y > extent.x) {
result = 1;
if (extent.z > extent.y)
result = 2;
- } else if (extent.z > extent.x)
+ }
+ else if(extent.z > extent.x)
result = 2;
return result;
}
@@ -871,9 +945,10 @@ struct AABB {
Vector3 min, max;
};
-struct ArrayBase {
- ArrayBase(uint32_t _elementSize, int memTag = MemTag::Default) :
- buffer(nullptr), elementSize(_elementSize), size(0), capacity(0) {
+struct ArrayBase
+{
+ ArrayBase(uint32_t _elementSize, int memTag = MemTag::Default) : buffer(nullptr), elementSize(_elementSize), size(0), capacity(0)
+ {
#if XA_DEBUG_HEAP
this->memTag = memTag;
#else
@@ -881,15 +956,18 @@ struct ArrayBase {
#endif
}
- ~ArrayBase() {
+ ~ArrayBase()
+ {
XA_FREE(buffer);
}
- XA_INLINE void clear() {
+ XA_INLINE void clear()
+ {
size = 0;
}
- void copyFrom(const uint8_t *data, uint32_t length) {
+ void copyFrom(const uint8_t *data, uint32_t length)
+ {
XA_DEBUG_ASSERT(data);
XA_DEBUG_ASSERT(length > 0);
resize(length, true);
@@ -897,7 +975,8 @@ struct ArrayBase {
memcpy(buffer, data, length * elementSize);
}
- void copyTo(ArrayBase &other) const {
+ void copyTo(ArrayBase &other) const
+ {
XA_DEBUG_ASSERT(elementSize == other.elementSize);
XA_DEBUG_ASSERT(size > 0);
other.resize(size, true);
@@ -905,7 +984,8 @@ struct ArrayBase {
memcpy(other.buffer, buffer, size * elementSize);
}
- void destroy() {
+ void destroy()
+ {
size = 0;
XA_FREE(buffer);
buffer = nullptr;
@@ -914,7 +994,8 @@ struct ArrayBase {
}
// Insert the given element at the given index shifting all the elements up.
- void insertAt(uint32_t index, const uint8_t *value) {
+ void insertAt(uint32_t index, const uint8_t *value)
+ {
XA_DEBUG_ASSERT(index >= 0 && index <= size);
XA_DEBUG_ASSERT(value);
resize(size + 1, false);
@@ -925,7 +1006,8 @@ struct ArrayBase {
memcpy(&buffer[index * elementSize], value, elementSize);
}
- void moveTo(ArrayBase &other) {
+ void moveTo(ArrayBase &other)
+ {
XA_DEBUG_ASSERT(elementSize == other.elementSize);
other.destroy();
other.buffer = buffer;
@@ -939,12 +1021,14 @@ struct ArrayBase {
elementSize = size = capacity = 0;
}
- void pop_back() {
+ void pop_back()
+ {
XA_DEBUG_ASSERT(size > 0);
resize(size - 1, false);
}
- void push_back(const uint8_t *value) {
+ void push_back(const uint8_t *value)
+ {
XA_DEBUG_ASSERT(value < buffer || value >= buffer + size);
XA_DEBUG_ASSERT(value);
resize(size + 1, false);
@@ -953,7 +1037,8 @@ struct ArrayBase {
memcpy(&buffer[(size - 1) * elementSize], value, elementSize);
}
- void push_back(const ArrayBase &other) {
+ void push_back(const ArrayBase &other)
+ {
XA_DEBUG_ASSERT(elementSize == other.elementSize);
if (other.size > 0) {
const uint32_t oldSize = size;
@@ -965,7 +1050,8 @@ struct ArrayBase {
}
// Remove the element at the given index. This is an expensive operation!
- void removeAt(uint32_t index) {
+ void removeAt(uint32_t index)
+ {
XA_DEBUG_ASSERT(index >= 0 && index < size);
XA_DEBUG_ASSERT(buffer);
if (buffer) {
@@ -977,7 +1063,8 @@ struct ArrayBase {
}
// Element at index is swapped with the last element, then the array length is decremented.
- void removeAtFast(uint32_t index) {
+ void removeAtFast(uint32_t index)
+ {
XA_DEBUG_ASSERT(index >= 0 && index < size);
XA_DEBUG_ASSERT(buffer);
if (buffer) {
@@ -988,12 +1075,14 @@ struct ArrayBase {
}
}
- void reserve(uint32_t desiredSize) {
+ void reserve(uint32_t desiredSize)
+ {
if (desiredSize > capacity)
setArrayCapacity(desiredSize);
}
- void resize(uint32_t newSize, bool exact) {
+ void resize(uint32_t newSize, bool exact)
+ {
size = newSize;
if (size > capacity) {
// First allocation is always exact. Otherwise, following allocations grow array to 150% of desired size.
@@ -1006,7 +1095,8 @@ struct ArrayBase {
}
}
- void setArrayCapacity(uint32_t newCapacity) {
+ void setArrayCapacity(uint32_t newCapacity)
+ {
XA_DEBUG_ASSERT(newCapacity >= size);
if (newCapacity == 0) {
// free the buffer.
@@ -1026,7 +1116,8 @@ struct ArrayBase {
}
#if XA_DEBUG_HEAP
- void setMemTag(int _memTag) {
+ void setMemTag(int _memTag)
+ {
this->memTag = _memTag;
}
#endif
@@ -1040,27 +1131,30 @@ struct ArrayBase {
#endif
};
-template <typename T>
-class Array {
+template<typename T>
+class Array
+{
public:
- Array(int memTag = MemTag::Default) :
- m_base(sizeof(T), memTag) {}
- Array(const Array &) = delete;
+ Array(int memTag = MemTag::Default) : m_base(sizeof(T), memTag) {}
+ Array(const Array&) = delete;
Array &operator=(const Array &) = delete;
- XA_INLINE const T &operator[](uint32_t index) const {
+ XA_INLINE const T &operator[](uint32_t index) const
+ {
XA_DEBUG_ASSERT(index < m_base.size);
XA_DEBUG_ASSERT(m_base.buffer);
return ((const T *)m_base.buffer)[index];
}
- XA_INLINE T &operator[](uint32_t index) {
+ XA_INLINE T &operator[](uint32_t index)
+ {
XA_DEBUG_ASSERT(index < m_base.size);
XA_DEBUG_ASSERT(m_base.buffer);
return ((T *)m_base.buffer)[index];
}
- XA_INLINE const T &back() const {
+ XA_INLINE const T &back() const
+ {
XA_DEBUG_ASSERT(!isEmpty());
return ((const T *)m_base.buffer)[m_base.size - 1];
}
@@ -1068,7 +1162,8 @@ public:
XA_INLINE T *begin() { return (T *)m_base.buffer; }
XA_INLINE void clear() { m_base.clear(); }
- bool contains(const T &value) const {
+ bool contains(const T &value) const
+ {
for (uint32_t i = 0; i < m_base.size; i++) {
if (((const T *)m_base.buffer)[i] == value)
return true;
@@ -1093,23 +1188,27 @@ public:
void reserve(uint32_t desiredSize) { m_base.reserve(desiredSize); }
void resize(uint32_t newSize) { m_base.resize(newSize, true); }
- void runCtors() {
+ void runCtors()
+ {
for (uint32_t i = 0; i < m_base.size; i++)
new (&((T *)m_base.buffer)[i]) T;
}
- void runDtors() {
+ void runDtors()
+ {
for (uint32_t i = 0; i < m_base.size; i++)
((T *)m_base.buffer)[i].~T();
}
- void fill(const T &value) {
+ void fill(const T &value)
+ {
auto buffer = (T *)m_base.buffer;
for (uint32_t i = 0; i < m_base.size; i++)
buffer[i] = value;
}
- void fillBytes(uint8_t value) {
+ void fillBytes(uint8_t value)
+ {
if (m_base.buffer && m_base.size > 0)
memset(m_base.buffer, (int)value, m_base.size * m_base.elementSize);
}
@@ -1120,7 +1219,8 @@ public:
XA_INLINE uint32_t size() const { return m_base.size; }
- XA_INLINE void zeroOutMemory() {
+ XA_INLINE void zeroOutMemory()
+ {
if (m_base.buffer && m_base.size > 0)
memset(m_base.buffer, 0, m_base.elementSize * m_base.size);
}
@@ -1129,57 +1229,37 @@ private:
ArrayBase m_base;
};
-template <typename T>
-struct ArrayView {
- ArrayView() :
- data(nullptr), length(0) {}
- ArrayView(Array<T> &a) :
- data(a.data()), length(a.size()) {}
- ArrayView(T *_data, uint32_t _length) :
- data(_data), length(_length) {}
- ArrayView &operator=(Array<T> &a) {
- data = a.data();
- length = a.size();
- return *this;
- }
- XA_INLINE const T &operator[](uint32_t index) const {
- XA_DEBUG_ASSERT(index < length);
- return data[index];
- }
- XA_INLINE T &operator[](uint32_t index) {
- XA_DEBUG_ASSERT(index < length);
- return data[index];
- }
+template<typename T>
+struct ArrayView
+{
+ ArrayView() : data(nullptr), length(0) {}
+ ArrayView(Array<T> &a) : data(a.data()), length(a.size()) {}
+ ArrayView(T *_data, uint32_t _length) : data(_data), length(_length) {}
+ ArrayView &operator=(Array<T> &a) { data = a.data(); length = a.size(); return *this; }
+ XA_INLINE const T &operator[](uint32_t index) const { XA_DEBUG_ASSERT(index < length); return data[index]; }
+ XA_INLINE T &operator[](uint32_t index) { XA_DEBUG_ASSERT(index < length); return data[index]; }
T *data;
uint32_t length;
};
-template <typename T>
-struct ConstArrayView {
- ConstArrayView() :
- data(nullptr), length(0) {}
- ConstArrayView(const Array<T> &a) :
- data(a.data()), length(a.size()) {}
- ConstArrayView(ArrayView<T> av) :
- data(av.data), length(av.length) {}
- ConstArrayView(const T *_data, uint32_t _length) :
- data(_data), length(_length) {}
- ConstArrayView &operator=(const Array<T> &a) {
- data = a.data();
- length = a.size();
- return *this;
- }
- XA_INLINE const T &operator[](uint32_t index) const {
- XA_DEBUG_ASSERT(index < length);
- return data[index];
- }
+template<typename T>
+struct ConstArrayView
+{
+ ConstArrayView() : data(nullptr), length(0) {}
+ ConstArrayView(const Array<T> &a) : data(a.data()), length(a.size()) {}
+ ConstArrayView(ArrayView<T> av) : data(av.data), length(av.length) {}
+ ConstArrayView(const T *_data, uint32_t _length) : data(_data), length(_length) {}
+ ConstArrayView &operator=(const Array<T> &a) { data = a.data(); length = a.size(); return *this; }
+ XA_INLINE const T &operator[](uint32_t index) const { XA_DEBUG_ASSERT(index < length); return data[index]; }
const T *data;
uint32_t length;
};
/// Basis class to compute tangent space basis, ortogonalizations and to transform vectors from one space to another.
-struct Basis {
- XA_NODISCARD static Vector3 computeTangent(const Vector3 &normal) {
+struct Basis
+{
+ XA_NODISCARD static Vector3 computeTangent(const Vector3 &normal)
+ {
XA_ASSERT(isNormalized(normal));
// Choose minimum axis.
Vector3 tangent;
@@ -1195,7 +1275,8 @@ struct Basis {
return tangent;
}
- XA_NODISCARD static Vector3 computeBitangent(const Vector3 &normal, const Vector3 &tangent) {
+ XA_NODISCARD static Vector3 computeBitangent(const Vector3 &normal, const Vector3 &tangent)
+ {
return cross(normal, tangent);
}
@@ -1205,36 +1286,42 @@ struct Basis {
};
// Simple bit array.
-class BitArray {
+class BitArray
+{
public:
- BitArray() :
- m_size(0) {}
+ BitArray() : m_size(0) {}
- BitArray(uint32_t sz) {
+ BitArray(uint32_t sz)
+ {
resize(sz);
}
- void resize(uint32_t new_size) {
+ void resize(uint32_t new_size)
+ {
m_size = new_size;
m_wordArray.resize((m_size + 31) >> 5);
}
- bool get(uint32_t index) const {
+ bool get(uint32_t index) const
+ {
XA_DEBUG_ASSERT(index < m_size);
return (m_wordArray[index >> 5] & (1 << (index & 31))) != 0;
}
- void set(uint32_t index) {
+ void set(uint32_t index)
+ {
XA_DEBUG_ASSERT(index < m_size);
m_wordArray[index >> 5] |= (1 << (index & 31));
}
- void unset(uint32_t index) {
+ void unset(uint32_t index)
+ {
XA_DEBUG_ASSERT(index < m_size);
m_wordArray[index >> 5] &= ~(1 << (index & 31));
}
- void zeroOutMemory() {
+ void zeroOutMemory()
+ {
m_wordArray.zeroOutMemory();
}
@@ -1243,13 +1330,13 @@ private:
Array<uint32_t> m_wordArray;
};
-class BitImage {
+class BitImage
+{
public:
- BitImage() :
- m_width(0), m_height(0), m_rowStride(0), m_data(MemTag::BitImage) {}
+ BitImage() : m_width(0), m_height(0), m_rowStride(0), m_data(MemTag::BitImage) {}
- BitImage(uint32_t w, uint32_t h) :
- m_width(w), m_height(h), m_data(MemTag::BitImage) {
+ BitImage(uint32_t w, uint32_t h) : m_width(w), m_height(h), m_data(MemTag::BitImage)
+ {
m_rowStride = (m_width + 63) >> 6;
m_data.resize(m_rowStride * m_height);
m_data.zeroOutMemory();
@@ -1260,14 +1347,16 @@ public:
uint32_t width() const { return m_width; }
uint32_t height() const { return m_height; }
- void copyTo(BitImage &other) {
+ void copyTo(BitImage &other)
+ {
other.m_width = m_width;
other.m_height = m_height;
other.m_rowStride = m_rowStride;
m_data.copyTo(other.m_data);
}
- void resize(uint32_t w, uint32_t h, bool discard) {
+ void resize(uint32_t w, uint32_t h, bool discard)
+ {
const uint32_t rowStride = (w + 63) >> 6;
if (discard) {
m_data.resize(rowStride * h);
@@ -1291,24 +1380,28 @@ public:
m_rowStride = rowStride;
}
- bool get(uint32_t x, uint32_t y) const {
+ bool get(uint32_t x, uint32_t y) const
+ {
XA_DEBUG_ASSERT(x < m_width && y < m_height);
const uint32_t index = (x >> 6) + y * m_rowStride;
return (m_data[index] & (UINT64_C(1) << (uint64_t(x) & UINT64_C(63)))) != 0;
}
- void set(uint32_t x, uint32_t y) {
+ void set(uint32_t x, uint32_t y)
+ {
XA_DEBUG_ASSERT(x < m_width && y < m_height);
const uint32_t index = (x >> 6) + y * m_rowStride;
m_data[index] |= UINT64_C(1) << (uint64_t(x) & UINT64_C(63));
XA_DEBUG_ASSERT(get(x, y));
}
- void zeroOutMemory() {
+ void zeroOutMemory()
+ {
m_data.zeroOutMemory();
}
- bool canBlit(const BitImage &image, uint32_t offsetX, uint32_t offsetY) const {
+ bool canBlit(const BitImage &image, uint32_t offsetX, uint32_t offsetY) const
+ {
for (uint32_t y = 0; y < image.m_height; y++) {
const uint32_t thisY = y + offsetY;
if (thisY >= m_height)
@@ -1332,7 +1425,8 @@ public:
return true;
}
- void dilate(uint32_t padding) {
+ void dilate(uint32_t padding)
+ {
BitImage tmp(m_width, m_height);
for (uint32_t p = 0; p < padding; p++) {
tmp.zeroOutMemory();
@@ -1342,21 +1436,15 @@ public:
if (!b) {
if (x > 0) {
b |= get(x - 1, y);
- if (y > 0)
- b |= get(x - 1, y - 1);
- if (y < m_height - 1)
- b |= get(x - 1, y + 1);
+ if (y > 0) b |= get(x - 1, y - 1);
+ if (y < m_height - 1) b |= get(x - 1, y + 1);
}
- if (y > 0)
- b |= get(x, y - 1);
- if (y < m_height - 1)
- b |= get(x, y + 1);
+ if (y > 0) b |= get(x, y - 1);
+ if (y < m_height - 1) b |= get(x, y + 1);
if (x < m_width - 1) {
b |= get(x + 1, y);
- if (y > 0)
- b |= get(x + 1, y - 1);
- if (y < m_height - 1)
- b |= get(x + 1, y + 1);
+ if (y > 0) b |= get(x + 1, y - 1);
+ if (y < m_height - 1) b |= get(x + 1, y + 1);
}
}
if (b)
@@ -1375,10 +1463,11 @@ private:
};
// From Fast-BVH
-class BVH {
+class BVH
+{
public:
- BVH(const Array<AABB> &objectAabbs, uint32_t leafSize = 4) :
- m_objectIds(MemTag::BVH), m_nodes(MemTag::BVH) {
+ BVH(const Array<AABB> &objectAabbs, uint32_t leafSize = 4) : m_objectIds(MemTag::BVH), m_nodes(MemTag::BVH)
+ {
m_objectAabbs = &objectAabbs;
if (m_objectAabbs->isEmpty())
return;
@@ -1398,7 +1487,7 @@ public:
Node node;
m_nodes.reserve(objectAabbs.size() * 2);
uint32_t nNodes = 0;
- while (stackptr > 0) {
+ while(stackptr > 0) {
// Pop the next item off of the stack
const BuildEntry &bnode = todo[--stackptr];
const uint32_t start = bnode.start;
@@ -1411,7 +1500,7 @@ public:
// Calculate the bounding box for this node
AABB bb(objectAabbs[m_objectIds[start]]);
AABB bc(objectAabbs[m_objectIds[start]].centroid());
- for (uint32_t p = start + 1; p < end; ++p) {
+ for(uint32_t p = start + 1; p < end; ++p) {
bb.expandToInclude(objectAabbs[m_objectIds[p]]);
bc.expandToInclude(objectAabbs[m_objectIds[p]].centroid());
}
@@ -1427,7 +1516,7 @@ public:
m_nodes[bnode.parent].rightOffset--;
// When this is the second touch, this is the right child.
// The right child sets up the offset for the flat tree.
- if (m_nodes[bnode.parent].rightOffset == kTouchedTwice)
+ if (m_nodes[bnode.parent].rightOffset == kTouchedTwice )
m_nodes[bnode.parent].rightOffset = nNodes - 1 - bnode.parent;
}
// If this is a leaf, no need to subdivide.
@@ -1462,20 +1551,21 @@ public:
}
}
- void query(const AABB &queryAabb, Array<uint32_t> &result) const {
+ void query(const AABB &queryAabb, Array<uint32_t> &result) const
+ {
result.clear();
// Working set
uint32_t todo[64];
int32_t stackptr = 0;
// "Push" on the root node to the working set
todo[stackptr] = 0;
- while (stackptr >= 0) {
+ while(stackptr >= 0) {
// Pop off the next node to work on.
const int ni = todo[stackptr--];
const Node &node = m_nodes[ni];
// Is leaf -> Intersect
if (node.rightOffset == 0) {
- for (uint32_t o = 0; o < node.nPrims; ++o) {
+ for(uint32_t o = 0; o < node.nPrims; ++o) {
const uint32_t obj = node.start + o;
if (queryAabb.intersect((*m_objectAabbs)[m_objectIds[obj]]))
result.push_back(m_objectIds[obj]);
@@ -1492,12 +1582,14 @@ public:
}
private:
- struct BuildEntry {
+ struct BuildEntry
+ {
uint32_t parent; // If non-zero then this is the index of the parent. (used in offsets)
uint32_t start, end; // The range of objects in the object list covered by this node.
};
- struct Node {
+ struct Node
+ {
AABB aabb;
uint32_t start, nPrims, rightOffset;
};
@@ -1507,8 +1599,10 @@ private:
Array<Node> m_nodes;
};
-struct Fit {
- static bool computeBasis(ConstArrayView<Vector3> points, Basis *basis) {
+struct Fit
+{
+ static bool computeBasis(ConstArrayView<Vector3> points, Basis *basis)
+ {
if (computeLeastSquaresNormal(points, &basis->normal)) {
basis->tangent = Basis::computeTangent(basis->normal);
basis->bitangent = Basis::computeBitangent(basis->normal, basis->tangent);
@@ -1522,7 +1616,8 @@ private:
// Fast, and accurate to within a few degrees.
// Returns None if the points do not span a plane.
// https://www.ilikebigbits.com/2015_03_04_plane_from_points.html
- static bool computeLeastSquaresNormal(ConstArrayView<Vector3> points, Vector3 *normal) {
+ static bool computeLeastSquaresNormal(ConstArrayView<Vector3> points, Vector3 *normal)
+ {
XA_DEBUG_ASSERT(points.length >= 3);
if (points.length == 3) {
*normal = normalize(cross(points[2] - points[0], points[1] - points[0]));
@@ -1587,7 +1682,7 @@ private:
// Pick path with best conditioning:
Vector3 dir(0.0f);
if (det_max == det_x)
- dir = Vector3(det_x, xz * yz - xy * zz, xy * yz - xz * yy);
+ dir = Vector3(det_x,xz * yz - xy * zz,xy * yz - xz * yy);
else if (det_max == det_y)
dir = Vector3(xz * yz - xy * zz, det_y, xy * xz - yz * xx);
else if (det_max == det_z)
@@ -1600,7 +1695,8 @@ private:
return isNormalized(*normal);
}
- static bool computeEigen(ConstArrayView<Vector3> points, Basis *basis) {
+ static bool computeEigen(ConstArrayView<Vector3> points, Basis *basis)
+ {
float matrix[6];
computeCovariance(points, matrix);
if (matrix[0] == 0 && matrix[3] == 0 && matrix[5] == 0)
@@ -1615,7 +1711,8 @@ private:
return true;
}
- static Vector3 computeCentroid(ConstArrayView<Vector3> points) {
+ static Vector3 computeCentroid(ConstArrayView<Vector3> points)
+ {
Vector3 centroid(0.0f);
for (uint32_t i = 0; i < points.length; i++)
centroid += points[i];
@@ -1623,7 +1720,8 @@ private:
return centroid;
}
- static Vector3 computeCovariance(ConstArrayView<Vector3> points, float *covariance) {
+ static Vector3 computeCovariance(ConstArrayView<Vector3> points, float * covariance)
+ {
// compute the centroid
Vector3 centroid = computeCentroid(points);
// compute covariance matrix
@@ -1645,7 +1743,8 @@ private:
// Tridiagonal solver from Charles Bloom.
// Householder transforms followed by QL decomposition.
// Seems to be based on the code from Numerical Recipes in C.
- static bool eigenSolveSymmetric3(const float matrix[6], float eigenValues[3], Vector3 eigenVectors[3]) {
+ static bool eigenSolveSymmetric3(const float matrix[6], float eigenValues[3], Vector3 eigenVectors[3])
+ {
XA_DEBUG_ASSERT(matrix != nullptr && eigenValues != nullptr && eigenVectors != nullptr);
float subd[3];
float diag[3];
@@ -1670,7 +1769,7 @@ private:
// eigenvectors are the columns; make them the rows :
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
- (&eigenVectors[j].x)[i] = (float)work[i][j];
+ (&eigenVectors[j].x)[i] = (float) work[i][j];
}
}
// shuffle to sort by singular value :
@@ -1692,7 +1791,8 @@ private:
}
private:
- static void EigenSolver3_Tridiagonal(float mat[3][3], float *diag, float *subd) {
+ static void EigenSolver3_Tridiagonal(float mat[3][3], float *diag, float *subd)
+ {
// Householder reduction T = Q^t M Q
// Input:
// mat, symmetric 3x3 matrix M
@@ -1744,7 +1844,8 @@ private:
}
}
- static bool EigenSolver3_QLAlgorithm(float mat[3][3], float *diag, float *subd) {
+ static bool EigenSolver3_QLAlgorithm(float mat[3][3], float *diag, float *subd)
+ {
// QL iteration with implicit shifting to reduce matrix from tridiagonal
// to diagonal
const int maxiter = 32;
@@ -1754,21 +1855,21 @@ private:
int m;
for (m = ell; m <= 1; m++) {
float dd = fabsf(diag[m]) + fabsf(diag[m + 1]);
- if (fabsf(subd[m]) + dd == dd)
+ if ( fabsf(subd[m]) + dd == dd )
break;
}
- if (m == ell)
+ if ( m == ell )
break;
float g = (diag[ell + 1] - diag[ell]) / (2 * subd[ell]);
float r = sqrtf(g * g + 1);
- if (g < 0)
+ if ( g < 0 )
g = diag[m] - diag[ell] + subd[ell] / (g - r);
else
g = diag[m] - diag[ell] + subd[ell] / (g + r);
float s = 1, c = 1, p = 0;
for (int i = m - 1; i >= ell; i--) {
float f = s * subd[i], b = c * subd[i];
- if (fabsf(f) >= fabsf(g)) {
+ if ( fabsf(f) >= fabsf(g) ) {
c = g / f;
r = sqrtf(c * c + 1);
subd[i + 1] = f * r;
@@ -1794,7 +1895,7 @@ private:
subd[ell] = g;
subd[m] = 0;
}
- if (iter == maxiter)
+ if ( iter == maxiter )
// should not get here under normal circumstances
return false;
}
@@ -1802,48 +1903,56 @@ private:
}
};
-static uint32_t sdbmHash(const void *data_in, uint32_t size, uint32_t h = 5381) {
- const uint8_t *data = (const uint8_t *)data_in;
+static uint32_t sdbmHash(const void *data_in, uint32_t size, uint32_t h = 5381)
+{
+ const uint8_t *data = (const uint8_t *) data_in;
uint32_t i = 0;
while (i < size) {
- h = (h << 16) + (h << 6) - h + (uint32_t)data[i++];
+ h = (h << 16) + (h << 6) - h + (uint32_t ) data[i++];
}
return h;
}
template <typename T>
-static uint32_t hash(const T &t, uint32_t h = 5381) {
+static uint32_t hash(const T &t, uint32_t h = 5381)
+{
return sdbmHash(&t, sizeof(T), h);
}
template <typename Key>
-struct Hash {
+struct Hash
+{
uint32_t operator()(const Key &k) const { return hash(k); }
};
template <typename Key>
-struct PassthroughHash {
+struct PassthroughHash
+{
uint32_t operator()(const Key &k) const { return (uint32_t)k; }
};
template <typename Key>
-struct Equal {
+struct Equal
+{
bool operator()(const Key &k0, const Key &k1) const { return k0 == k1; }
};
-template <typename Key, typename H = Hash<Key>, typename E = Equal<Key>>
-class HashMap {
+template<typename Key, typename H = Hash<Key>, typename E = Equal<Key> >
+class HashMap
+{
public:
- HashMap(int memTag, uint32_t size) :
- m_memTag(memTag), m_size(size), m_numSlots(0), m_slots(nullptr), m_keys(memTag), m_next(memTag) {
+ HashMap(int memTag, uint32_t size) : m_memTag(memTag), m_size(size), m_numSlots(0), m_slots(nullptr), m_keys(memTag), m_next(memTag)
+ {
}
- ~HashMap() {
+ ~HashMap()
+ {
if (m_slots)
XA_FREE(m_slots);
}
- void destroy() {
+ void destroy()
+ {
if (m_slots) {
XA_FREE(m_slots);
m_slots = nullptr;
@@ -1852,7 +1961,8 @@ public:
m_next.destroy();
}
- uint32_t add(const Key &key) {
+ uint32_t add(const Key &key)
+ {
if (!m_slots)
alloc();
const uint32_t hash = computeHash(key);
@@ -1862,18 +1972,21 @@ public:
return m_keys.size() - 1;
}
- uint32_t get(const Key &key) const {
+ uint32_t get(const Key &key) const
+ {
if (!m_slots)
return UINT32_MAX;
return find(key, m_slots[computeHash(key)]);
}
- uint32_t getNext(const Key &key, uint32_t current) const {
+ uint32_t getNext(const Key &key, uint32_t current) const
+ {
return find(key, m_next[current]);
}
private:
- void alloc() {
+ void alloc()
+ {
XA_DEBUG_ASSERT(m_size > 0);
m_numSlots = nextPowerOfTwo(m_size);
auto minNumSlots = uint32_t(m_size * 1.3);
@@ -1886,12 +1999,14 @@ private:
m_next.reserve(m_size);
}
- uint32_t computeHash(const Key &key) const {
+ uint32_t computeHash(const Key &key) const
+ {
H hash;
return hash(key) & (m_numSlots - 1);
}
- uint32_t find(const Key &key, uint32_t current) const {
+ uint32_t find(const Key &key, uint32_t current) const
+ {
E equal;
while (current != UINT32_MAX) {
if (equal(m_keys[current], key))
@@ -1909,8 +2024,9 @@ private:
Array<uint32_t> m_next;
};
-template <typename T>
-static void insertionSort(T *data, uint32_t length) {
+template<typename T>
+static void insertionSort(T *data, uint32_t length)
+{
for (int32_t i = 1; i < (int32_t)length; i++) {
T x = data[i];
int32_t j = i - 1;
@@ -1922,18 +2038,21 @@ static void insertionSort(T *data, uint32_t length) {
}
}
-class KISSRng {
+class KISSRng
+{
public:
KISSRng() { reset(); }
- void reset() {
+ void reset()
+ {
x = 123456789;
y = 362436000;
z = 521288629;
c = 7654321;
}
- uint32_t getRange(uint32_t range) {
+ uint32_t getRange(uint32_t range)
+ {
if (range == 0)
return 0;
x = 69069 * x + 12345;
@@ -1952,9 +2071,11 @@ private:
// Based on Pierre Terdiman's and Michael Herf's source code.
// http://www.codercorner.com/RadixSortRevisited.htm
// http://www.stereopsis.com/radix.html
-class RadixSort {
+class RadixSort
+{
public:
- void sort(ConstArrayView<float> input) {
+ void sort(ConstArrayView<float> input)
+ {
if (input.length == 0) {
m_buffer1.clear();
m_buffer2.clear();
@@ -1983,7 +2104,8 @@ public:
}
// Access to results. m_ranks is a list of indices in sorted order, i.e. in the order you may further process your data
- const uint32_t *ranks() const {
+ const uint32_t *ranks() const
+ {
XA_DEBUG_ASSERT(m_validRanks);
return m_ranks;
}
@@ -1993,17 +2115,20 @@ private:
Array<uint32_t> m_buffer1, m_buffer2;
bool m_validRanks = false;
- void floatFlip(uint32_t &f) {
+ void floatFlip(uint32_t &f)
+ {
int32_t mask = (int32_t(f) >> 31) | 0x80000000; // Warren Hunt, Manchor Ko.
f ^= mask;
}
- void ifloatFlip(uint32_t &f) {
+ void ifloatFlip(uint32_t &f)
+ {
uint32_t mask = ((f >> 31) - 1) | 0x80000000; // Michael Herf.
f ^= mask;
}
- void createHistograms(ConstArrayView<uint32_t> input, uint32_t *histogram) {
+ void createHistograms(ConstArrayView<uint32_t> input, uint32_t *histogram)
+ {
const uint32_t bucketCount = sizeof(uint32_t);
// Init bucket pointers.
uint32_t *h[bucketCount];
@@ -2014,14 +2139,15 @@ private:
memset(histogram, 0, 256 * bucketCount * sizeof(uint32_t));
// @@ Add support for signed integers.
// Build histograms.
- const uint8_t *p = (const uint8_t *)input.data; // @@ Does this break aliasing rules?
+ const uint8_t *p = (const uint8_t *)input.data; // @@ Does this break aliasing rules?
const uint8_t *pe = p + input.length * sizeof(uint32_t);
while (p != pe) {
h[0][*p++]++, h[1][*p++]++, h[2][*p++]++, h[3][*p++]++;
}
}
- void insertionSort(ConstArrayView<float> input) {
+ void insertionSort(ConstArrayView<float> input)
+ {
if (!m_validRanks) {
m_ranks[0] = 0;
for (uint32_t i = 1; i != input.length; ++i) {
@@ -2051,7 +2177,8 @@ private:
}
}
- void radixSort(ConstArrayView<uint32_t> input) {
+ void radixSort(ConstArrayView<uint32_t> input)
+ {
const uint32_t P = sizeof(uint32_t); // pass count
// Allocate histograms & offsets on the stack
uint32_t histogram[256 * P];
@@ -2069,8 +2196,7 @@ private:
}
// Create offsets
link[0] = m_ranks2;
- for (uint32_t i = 1; i < 256; i++)
- link[i] = link[i - 1] + h[i - 1];
+ for (uint32_t i = 1; i < 256; i++) link[i] = link[i - 1] + h[i - 1];
// Perform Radix Sort
if (!m_validRanks) {
for (uint32_t i = 0; i < input.length; i++) {
@@ -2096,21 +2222,25 @@ private:
};
// Wrapping this in a class allows temporary arrays to be re-used.
-class BoundingBox2D {
+class BoundingBox2D
+{
public:
Vector2 majorAxis, minorAxis, minCorner, maxCorner;
- void clear() {
+ void clear()
+ {
m_boundaryVertices.clear();
}
- void appendBoundaryVertex(Vector2 v) {
+ void appendBoundaryVertex(Vector2 v)
+ {
m_boundaryVertices.push_back(v);
}
// This should compute convex hull and use rotating calipers to find the best box. Currently it uses a brute force method.
// If vertices are empty, the boundary vertices are used.
- void compute(ConstArrayView<Vector2> vertices = ConstArrayView<Vector2>()) {
+ void compute(ConstArrayView<Vector2> vertices = ConstArrayView<Vector2>())
+ {
XA_DEBUG_ASSERT(!m_boundaryVertices.isEmpty());
if (vertices.length == 0)
vertices = m_boundaryVertices;
@@ -2157,7 +2287,8 @@ public:
private:
// Compute the convex hull using Graham Scan.
- void convexHull(ConstArrayView<Vector2> input, Array<Vector2> &output, float epsilon) {
+ void convexHull(ConstArrayView<Vector2> input, Array<Vector2> &output, float epsilon)
+ {
m_coords.resize(input.length);
for (uint32_t i = 0; i < input.length; i++)
m_coords[i] = input[i].x;
@@ -2186,7 +2317,7 @@ private:
XA_DEBUG_ASSERT(m_top.size() >= 2);
output.push_back(m_top[0]);
output.push_back(m_top[1]);
- for (uint32_t i = 2; i < m_top.size();) {
+ for (uint32_t i = 2; i < m_top.size(); ) {
Vector2 a = output[output.size() - 2];
Vector2 b = output[output.size() - 1];
Vector2 c = m_top[i];
@@ -2202,7 +2333,7 @@ private:
XA_DEBUG_ASSERT(m_bottom.size() >= 2);
output.push_back(m_bottom[1]);
// Filter bottom list.
- for (uint32_t i = 2; i < m_bottom.size();) {
+ for (uint32_t i = 2; i < m_bottom.size(); ) {
Vector2 a = output[output.size() - 2];
Vector2 b = output[output.size() - 1];
Vector2 c = m_bottom[i];
@@ -2225,45 +2356,45 @@ private:
RadixSort m_radix;
};
-struct EdgeKey {
- EdgeKey(const EdgeKey &k) :
- v0(k.v0), v1(k.v1) {}
- EdgeKey(uint32_t _v0, uint32_t _v1) :
- v0(_v0), v1(_v1) {}
+struct EdgeKey
+{
+ EdgeKey(const EdgeKey &k) : v0(k.v0), v1(k.v1) {}
+ EdgeKey(uint32_t _v0, uint32_t _v1) : v0(_v0), v1(_v1) {}
bool operator==(const EdgeKey &k) const { return v0 == k.v0 && v1 == k.v1; }
uint32_t v0;
uint32_t v1;
};
-struct EdgeHash {
+struct EdgeHash
+{
uint32_t operator()(const EdgeKey &k) const { return k.v0 * 32768u + k.v1; }
};
-static uint32_t meshEdgeFace(uint32_t edge) {
- return edge / 3;
-}
-static uint32_t meshEdgeIndex0(uint32_t edge) {
- return edge;
-}
+static uint32_t meshEdgeFace(uint32_t edge) { return edge / 3; }
+static uint32_t meshEdgeIndex0(uint32_t edge) { return edge; }
-static uint32_t meshEdgeIndex1(uint32_t edge) {
+static uint32_t meshEdgeIndex1(uint32_t edge)
+{
const uint32_t faceFirstEdge = edge / 3 * 3;
return faceFirstEdge + (edge - faceFirstEdge + 1) % 3;
}
-struct MeshFlags {
- enum {
- HasIgnoredFaces = 1 << 0,
- HasNormals = 1 << 1,
- HasMaterials = 1 << 2
+struct MeshFlags
+{
+ enum
+ {
+ HasIgnoredFaces = 1<<0,
+ HasNormals = 1<<1,
+ HasMaterials = 1<<2
};
};
-class Mesh {
+class Mesh
+{
public:
- Mesh(float epsilon, uint32_t approxVertexCount, uint32_t approxFaceCount, uint32_t flags = 0, uint32_t id = UINT32_MAX) :
- m_epsilon(epsilon), m_flags(flags), m_id(id), m_faceIgnore(MemTag::Mesh), m_faceMaterials(MemTag::Mesh), m_indices(MemTag::MeshIndices), m_positions(MemTag::MeshPositions), m_normals(MemTag::MeshNormals), m_texcoords(MemTag::MeshTexcoords), m_nextColocalVertex(MemTag::MeshColocals), m_firstColocalVertex(MemTag::MeshColocals), m_boundaryEdges(MemTag::MeshBoundaries), m_oppositeEdges(MemTag::MeshBoundaries), m_edgeMap(MemTag::MeshEdgeMap, approxFaceCount * 3) {
+ Mesh(float epsilon, uint32_t approxVertexCount, uint32_t approxFaceCount, uint32_t flags = 0, uint32_t id = UINT32_MAX) : m_epsilon(epsilon), m_flags(flags), m_id(id), m_faceIgnore(MemTag::Mesh), m_faceMaterials(MemTag::Mesh), m_indices(MemTag::MeshIndices), m_positions(MemTag::MeshPositions), m_normals(MemTag::MeshNormals), m_texcoords(MemTag::MeshTexcoords), m_nextColocalVertex(MemTag::MeshColocals), m_firstColocalVertex(MemTag::MeshColocals), m_boundaryEdges(MemTag::MeshBoundaries), m_oppositeEdges(MemTag::MeshBoundaries), m_edgeMap(MemTag::MeshEdgeMap, approxFaceCount * 3)
+ {
m_indices.reserve(approxFaceCount * 3);
m_positions.reserve(approxVertexCount);
m_texcoords.reserve(approxVertexCount);
@@ -2278,7 +2409,8 @@ public:
uint32_t flags() const { return m_flags; }
uint32_t id() const { return m_id; }
- void addVertex(const Vector3 &pos, const Vector3 &normal = Vector3(0.0f), const Vector2 &texcoord = Vector2(0.0f)) {
+ void addVertex(const Vector3 &pos, const Vector3 &normal = Vector3(0.0f), const Vector2 &texcoord = Vector2(0.0f))
+ {
XA_DEBUG_ASSERT(isFinite(pos));
m_positions.push_back(pos);
if (m_flags & MeshFlags::HasNormals)
@@ -2286,7 +2418,8 @@ public:
m_texcoords.push_back(texcoord);
}
- void addFace(const uint32_t *indices, bool ignore = false, uint32_t material = UINT32_MAX) {
+ void addFace(const uint32_t *indices, bool ignore = false, uint32_t material = UINT32_MAX)
+ {
if (m_flags & MeshFlags::HasIgnoredFaces)
m_faceIgnore.push_back(ignore);
if (m_flags & MeshFlags::HasMaterials)
@@ -2301,7 +2434,8 @@ public:
}
}
- void createColocalsBVH() {
+ void createColocalsBVH()
+ {
const uint32_t vertexCount = m_positions.size();
Array<AABB> aabbs(MemTag::BVH);
aabbs.resize(vertexCount);
@@ -2342,7 +2476,8 @@ public:
}
}
- void createColocalsHash() {
+ void createColocalsHash()
+ {
const uint32_t vertexCount = m_positions.size();
HashMap<Vector3> positionToVertexMap(MemTag::Default, vertexCount);
for (uint32_t i = 0; i < vertexCount; i++)
@@ -2380,14 +2515,16 @@ public:
}
}
- void createColocals() {
+ void createColocals()
+ {
if (m_epsilon <= FLT_EPSILON)
createColocalsHash();
else
createColocalsBVH();
}
- void createBoundaries() {
+ void createBoundaries()
+ {
const uint32_t edgeCount = m_indices.size();
const uint32_t vertexCount = m_positions.size();
m_oppositeEdges.resize(edgeCount);
@@ -2418,7 +2555,8 @@ public:
}
/// Find edge, test all colocals.
- uint32_t findEdge(uint32_t vertex0, uint32_t vertex1) const {
+ uint32_t findEdge(uint32_t vertex0, uint32_t vertex1) const
+ {
// Try to find exact vertex match first.
{
EdgeKey key(vertex0, vertex1);
@@ -2459,12 +2597,14 @@ public:
// Edge map can be destroyed when no longer used to reduce memory usage. It's used by:
// * Mesh::createBoundaries()
// * Mesh::edgeMap() (used by MeshFaceGroups)
- void destroyEdgeMap() {
+ void destroyEdgeMap()
+ {
m_edgeMap.destroy();
}
#if XA_DEBUG_EXPORT_OBJ
- void writeObjVertices(FILE *file) const {
+ void writeObjVertices(FILE *file) const
+ {
for (uint32_t i = 0; i < m_positions.size(); i++)
fprintf(file, "v %g %g %g\n", m_positions[i].x, m_positions[i].y, m_positions[i].z);
if (m_flags & MeshFlags::HasNormals) {
@@ -2475,7 +2615,8 @@ public:
fprintf(file, "vt %g %g\n", m_texcoords[i].x, m_texcoords[i].y);
}
- void writeObjFace(FILE *file, uint32_t face, uint32_t offset = 0) const {
+ void writeObjFace(FILE *file, uint32_t face, uint32_t offset = 0) const
+ {
fprintf(file, "f ");
for (uint32_t j = 0; j < 3; j++) {
const uint32_t index = m_indices[face * 3 + j] + 1 + offset; // 1-indexed
@@ -2483,7 +2624,8 @@ public:
}
}
- void writeObjBoundaryEges(FILE *file) const {
+ void writeObjBoundaryEges(FILE *file) const
+ {
if (m_oppositeEdges.isEmpty())
return; // Boundaries haven't been created.
fprintf(file, "o boundary_edges\n");
@@ -2494,7 +2636,8 @@ public:
}
}
- void writeObjFile(const char *filename) const {
+ void writeObjFile(const char *filename) const
+ {
FILE *file;
XA_FOPEN(file, filename, "w");
if (!file)
@@ -2509,7 +2652,8 @@ public:
}
#endif
- float computeSurfaceArea() const {
+ float computeSurfaceArea() const
+ {
float area = 0;
for (uint32_t f = 0; f < faceCount(); f++)
area += computeFaceArea(f);
@@ -2518,21 +2662,24 @@ public:
}
// Returned value is always positive, even if some triangles are flipped.
- float computeParametricArea() const {
+ float computeParametricArea() const
+ {
float area = 0;
for (uint32_t f = 0; f < faceCount(); f++)
area += fabsf(computeFaceParametricArea(f)); // May be negative, depends on texcoord winding.
return area;
}
- float computeFaceArea(uint32_t face) const {
+ float computeFaceArea(uint32_t face) const
+ {
const Vector3 &p0 = m_positions[m_indices[face * 3 + 0]];
const Vector3 &p1 = m_positions[m_indices[face * 3 + 1]];
const Vector3 &p2 = m_positions[m_indices[face * 3 + 2]];
return length(cross(p1 - p0, p2 - p0)) * 0.5f;
}
- Vector3 computeFaceCentroid(uint32_t face) const {
+ Vector3 computeFaceCentroid(uint32_t face) const
+ {
Vector3 sum(0.0f);
for (uint32_t i = 0; i < 3; i++)
sum += m_positions[m_indices[face * 3 + i]];
@@ -2541,7 +2688,8 @@ public:
// Average of the edge midpoints weighted by the edge length.
// I want a point inside the triangle, but closer to the cirumcenter.
- Vector3 computeFaceCenter(uint32_t face) const {
+ Vector3 computeFaceCenter(uint32_t face) const
+ {
const Vector3 &p0 = m_positions[m_indices[face * 3 + 0]];
const Vector3 &p1 = m_positions[m_indices[face * 3 + 1]];
const Vector3 &p2 = m_positions[m_indices[face * 3 + 2]];
@@ -2554,7 +2702,8 @@ public:
return m0 + m1 + m2;
}
- Vector3 computeFaceNormal(uint32_t face) const {
+ Vector3 computeFaceNormal(uint32_t face) const
+ {
const Vector3 &p0 = m_positions[m_indices[face * 3 + 0]];
const Vector3 &p1 = m_positions[m_indices[face * 3 + 1]];
const Vector3 &p2 = m_positions[m_indices[face * 3 + 2]];
@@ -2564,7 +2713,8 @@ public:
return normalizeSafe(normalAreaScaled, Vector3(0, 0, 1));
}
- float computeFaceParametricArea(uint32_t face) const {
+ float computeFaceParametricArea(uint32_t face) const
+ {
const Vector2 &t0 = m_texcoords[m_indices[face * 3 + 0]];
const Vector2 &t1 = m_texcoords[m_indices[face * 3 + 1]];
const Vector2 &t2 = m_texcoords[m_indices[face * 3 + 2]];
@@ -2572,7 +2722,8 @@ public:
}
// @@ This is not exactly accurate, we should compare the texture coordinates...
- bool isSeam(uint32_t edge) const {
+ bool isSeam(uint32_t edge) const
+ {
const uint32_t oppositeEdge = m_oppositeEdges[edge];
if (oppositeEdge == UINT32_MAX)
return false; // boundary edge
@@ -2583,7 +2734,8 @@ public:
return m_indices[e0] != m_indices[oe1] || m_indices[e1] != m_indices[oe0];
}
- bool isTextureSeam(uint32_t edge) const {
+ bool isTextureSeam(uint32_t edge) const
+ {
const uint32_t oppositeEdge = m_oppositeEdges[edge];
if (oppositeEdge == UINT32_MAX)
return false; // boundary edge
@@ -2594,7 +2746,8 @@ public:
return m_texcoords[m_indices[e0]] != m_texcoords[m_indices[oe1]] || m_texcoords[m_indices[e1]] != m_texcoords[m_indices[oe0]];
}
- uint32_t firstColocalVertex(uint32_t vertex) const {
+ uint32_t firstColocalVertex(uint32_t vertex) const
+ {
XA_DEBUG_ASSERT(m_firstColocalVertex.size() == m_positions.size());
return m_firstColocalVertex[vertex];
}
@@ -2609,10 +2762,7 @@ public:
XA_INLINE uint32_t vertexAt(uint32_t i) const { return m_indices[i]; }
XA_INLINE const Vector3 &position(uint32_t vertex) const { return m_positions[vertex]; }
XA_INLINE ConstArrayView<Vector3> positions() const { return m_positions; }
- XA_INLINE const Vector3 &normal(uint32_t vertex) const {
- XA_DEBUG_ASSERT(m_flags & MeshFlags::HasNormals);
- return m_normals[vertex];
- }
+ XA_INLINE const Vector3 &normal(uint32_t vertex) const { XA_DEBUG_ASSERT(m_flags & MeshFlags::HasNormals); return m_normals[vertex]; }
XA_INLINE const Vector2 &texcoord(uint32_t vertex) const { return m_texcoords[vertex]; }
XA_INLINE Vector2 &texcoord(uint32_t vertex) { return m_texcoords[vertex]; }
XA_INLINE const ConstArrayView<Vector2> texcoords() const { return m_texcoords; }
@@ -2625,6 +2775,7 @@ public:
XA_INLINE const HashMap<EdgeKey, EdgeHash> &edgeMap() const { return m_edgeMap; }
private:
+
float m_epsilon;
uint32_t m_flags;
uint32_t m_id;
@@ -2647,21 +2798,24 @@ private:
HashMap<EdgeKey, EdgeHash> m_edgeMap;
public:
- class FaceEdgeIterator {
+ class FaceEdgeIterator
+ {
public:
- FaceEdgeIterator(const Mesh *mesh, uint32_t face) :
- m_mesh(mesh), m_face(face), m_relativeEdge(0) {
+ FaceEdgeIterator (const Mesh *mesh, uint32_t face) : m_mesh(mesh), m_face(face), m_relativeEdge(0)
+ {
m_edge = m_face * 3;
}
- void advance() {
+ void advance()
+ {
if (m_relativeEdge < 3) {
m_edge++;
m_relativeEdge++;
}
}
- bool isDone() const {
+ bool isDone() const
+ {
return m_relativeEdge == 3;
}
@@ -2673,7 +2827,8 @@ public:
uint32_t face() const { return m_face; }
uint32_t oppositeEdge() const { return m_mesh->m_oppositeEdges[m_edge]; }
- uint32_t oppositeFace() const {
+ uint32_t oppositeFace() const
+ {
const uint32_t oedge = m_mesh->m_oppositeEdges[m_edge];
if (oedge == UINT32_MAX)
return UINT32_MAX;
@@ -2697,18 +2852,19 @@ public:
};
};
-struct MeshFaceGroups {
+struct MeshFaceGroups
+{
typedef uint32_t Handle;
static constexpr Handle kInvalid = UINT32_MAX;
- MeshFaceGroups(const Mesh *mesh) :
- m_mesh(mesh), m_groups(MemTag::Mesh), m_firstFace(MemTag::Mesh), m_nextFace(MemTag::Mesh), m_faceCount(MemTag::Mesh) {}
+ MeshFaceGroups(const Mesh *mesh) : m_mesh(mesh), m_groups(MemTag::Mesh), m_firstFace(MemTag::Mesh), m_nextFace(MemTag::Mesh), m_faceCount(MemTag::Mesh) {}
XA_INLINE Handle groupAt(uint32_t face) const { return m_groups[face]; }
XA_INLINE uint32_t groupCount() const { return m_faceCount.size(); }
XA_INLINE uint32_t nextFace(uint32_t face) const { return m_nextFace[face]; }
XA_INLINE uint32_t faceCount(uint32_t group) const { return m_faceCount[group]; }
- void compute() {
+ void compute()
+ {
m_groups.resize(m_mesh->faceCount());
m_groups.fillBytes(0xff); // Set all faces to kInvalid
uint32_t firstUnassignedFace = 0;
@@ -2767,23 +2923,27 @@ struct MeshFaceGroups {
}
}
- class Iterator {
+ class Iterator
+ {
public:
- Iterator(const MeshFaceGroups *meshFaceGroups, Handle group) :
- m_meshFaceGroups(meshFaceGroups) {
+ Iterator(const MeshFaceGroups *meshFaceGroups, Handle group) : m_meshFaceGroups(meshFaceGroups)
+ {
XA_DEBUG_ASSERT(group != kInvalid);
m_current = m_meshFaceGroups->m_firstFace[group];
}
- void advance() {
+ void advance()
+ {
m_current = m_meshFaceGroups->m_nextFace[m_current];
}
- bool isDone() const {
+ bool isDone() const
+ {
return m_current == UINT32_MAX;
}
- uint32_t face() const {
+ uint32_t face() const
+ {
return m_current;
}
@@ -2803,7 +2963,8 @@ private:
constexpr MeshFaceGroups::Handle MeshFaceGroups::kInvalid;
#if XA_CHECK_T_JUNCTIONS
-static bool lineIntersectsPoint(const Vector3 &point, const Vector3 &lineStart, const Vector3 &lineEnd, float *t, float epsilon) {
+static bool lineIntersectsPoint(const Vector3 &point, const Vector3 &lineStart, const Vector3 &lineEnd, float *t, float epsilon)
+{
float tt;
if (!t)
t = &tt;
@@ -2821,7 +2982,8 @@ static bool lineIntersectsPoint(const Vector3 &point, const Vector3 &lineStart,
}
// Returns the number of T-junctions found.
-static int meshCheckTJunctions(const Mesh &inputMesh) {
+static int meshCheckTJunctions(const Mesh &inputMesh)
+{
int count = 0;
const uint32_t vertexCount = inputMesh.vertexCount();
const uint32_t edgeCount = inputMesh.edgeCount();
@@ -2845,10 +3007,12 @@ static int meshCheckTJunctions(const Mesh &inputMesh) {
#endif
// References invalid faces and vertices in a mesh.
-struct InvalidMeshGeometry {
+struct InvalidMeshGeometry
+{
// If meshFaceGroups is not null, invalid faces have the face group MeshFaceGroups::kInvalid.
// If meshFaceGroups is null, invalid faces are Mesh::isFaceIgnored.
- void extract(const Mesh *mesh, const MeshFaceGroups *meshFaceGroups) {
+ void extract(const Mesh *mesh, const MeshFaceGroups *meshFaceGroups)
+ {
// Copy invalid faces.
m_faces.clear();
const uint32_t meshFaceCount = mesh->faceCount();
@@ -2886,28 +3050,32 @@ private:
Array<uint32_t> m_vertexToSourceVertexMap; // Map face vertices to vertices of the source mesh.
};
-struct Progress {
- Progress(ProgressCategory category, ProgressFunc func, void *userData, uint32_t maxValue) :
- cancel(false), m_category(category), m_func(func), m_userData(userData), m_value(0), m_maxValue(maxValue), m_percent(0) {
+struct Progress
+{
+ Progress(ProgressCategory category, ProgressFunc func, void *userData, uint32_t maxValue) : cancel(false), m_category(category), m_func(func), m_userData(userData), m_value(0), m_maxValue(maxValue), m_percent(0)
+ {
if (m_func) {
if (!m_func(category, 0, userData))
cancel = true;
}
}
- ~Progress() {
+ ~Progress()
+ {
if (m_func) {
if (!m_func(m_category, 100, m_userData))
cancel = true;
}
}
- void increment(uint32_t value) {
+ void increment(uint32_t value)
+ {
m_value += value;
update();
}
- void setMaxValue(uint32_t maxValue) {
+ void setMaxValue(uint32_t maxValue)
+ {
m_maxValue = maxValue;
update();
}
@@ -2915,15 +3083,15 @@ struct Progress {
std::atomic<bool> cancel;
private:
- void update() {
+ void update()
+ {
if (!m_func)
return;
const uint32_t newPercent = uint32_t(ceilf(m_value.load() / (float)m_maxValue.load() * 100.0f));
if (newPercent != m_percent) {
// Atomic max.
uint32_t oldPercent = m_percent;
- while (oldPercent < newPercent && !m_percent.compare_exchange_weak(oldPercent, newPercent)) {
- }
+ while (oldPercent < newPercent && !m_percent.compare_exchange_weak(oldPercent, newPercent)) {}
if (!m_func(m_category, m_percent, m_userData))
cancel = true;
}
@@ -2935,31 +3103,32 @@ private:
std::atomic<uint32_t> m_value, m_maxValue, m_percent;
};
-struct Spinlock {
- void lock() {
- while (m_lock.test_and_set(std::memory_order_acquire)) {
- }
- }
+struct Spinlock
+{
+ void lock() { while(m_lock.test_and_set(std::memory_order_acquire)) {} }
void unlock() { m_lock.clear(std::memory_order_release); }
private:
std::atomic_flag m_lock = ATOMIC_FLAG_INIT;
};
-struct TaskGroupHandle {
+struct TaskGroupHandle
+{
uint32_t value = UINT32_MAX;
};
-struct Task {
+struct Task
+{
void (*func)(void *groupUserData, void *taskUserData);
void *userData; // Passed to func as taskUserData.
};
#if XA_MULTITHREADED
-class TaskScheduler {
+class TaskScheduler
+{
public:
- TaskScheduler() :
- m_shutdown(false) {
+ TaskScheduler() : m_shutdown(false)
+ {
m_threadIndex = 0;
// Max with current task scheduler usage is 1 per thread + 1 deep nesting, but allow for some slop.
m_maxGroups = std::thread::hardware_concurrency() * 4;
@@ -2978,7 +3147,8 @@ public:
}
}
- ~TaskScheduler() {
+ ~TaskScheduler()
+ {
m_shutdown = true;
for (uint32_t i = 0; i < m_workers.size(); i++) {
Worker &worker = m_workers[i];
@@ -2996,12 +3166,14 @@ public:
XA_FREE(m_groups);
}
- uint32_t threadCount() const {
+ uint32_t threadCount() const
+ {
return max(1u, std::thread::hardware_concurrency()); // Including the main thread.
}
// userData is passed to Task::func as groupUserData.
- TaskGroupHandle createTaskGroup(void *userData = nullptr, uint32_t reserveSize = 0) {
+ TaskGroupHandle createTaskGroup(void *userData = nullptr, uint32_t reserveSize = 0)
+ {
// Claim the first free group.
for (uint32_t i = 0; i < m_maxGroups; i++) {
TaskGroup &group = m_groups[i];
@@ -3025,7 +3197,8 @@ public:
return handle;
}
- void run(TaskGroupHandle handle, const Task &task) {
+ void run(TaskGroupHandle handle, const Task &task)
+ {
XA_DEBUG_ASSERT(handle.value != UINT32_MAX);
TaskGroup &group = m_groups[handle.value];
group.queueLock.lock();
@@ -3039,7 +3212,8 @@ public:
}
}
- void wait(TaskGroupHandle *handle) {
+ void wait(TaskGroupHandle *handle)
+ {
if (handle->value == UINT32_MAX) {
XA_DEBUG_ASSERT(false);
return;
@@ -3067,7 +3241,8 @@ public:
static uint32_t currentThreadIndex() { return m_threadIndex; }
private:
- struct TaskGroup {
+ struct TaskGroup
+ {
std::atomic<bool> free;
Array<Task> queue; // Items are never removed. queueHead is incremented to pop items.
uint32_t queueHead = 0;
@@ -3076,7 +3251,8 @@ private:
void *userData;
};
- struct Worker {
+ struct Worker
+ {
std::thread *thread = nullptr;
std::mutex mutex;
std::condition_variable cv;
@@ -3089,11 +3265,12 @@ private:
uint32_t m_maxGroups;
static thread_local uint32_t m_threadIndex;
- static void workerThread(TaskScheduler *scheduler, Worker *worker, uint32_t threadIndex) {
+ static void workerThread(TaskScheduler *scheduler, Worker *worker, uint32_t threadIndex)
+ {
m_threadIndex = threadIndex;
std::unique_lock<std::mutex> lock(worker->mutex);
for (;;) {
- worker->cv.wait(lock, [=] { return worker->wakeup.load(); });
+ worker->cv.wait(lock, [=]{ return worker->wakeup.load(); });
worker->wakeup = false;
for (;;) {
if (scheduler->m_shutdown)
@@ -3124,18 +3301,22 @@ private:
thread_local uint32_t TaskScheduler::m_threadIndex;
#else
-class TaskScheduler {
+class TaskScheduler
+{
public:
- ~TaskScheduler() {
+ ~TaskScheduler()
+ {
for (uint32_t i = 0; i < m_groups.size(); i++)
destroyGroup({ i });
}
- uint32_t threadCount() const {
+ uint32_t threadCount() const
+ {
return 1;
}
- TaskGroupHandle createTaskGroup(void *userData = nullptr, uint32_t reserveSize = 0) {
+ TaskGroupHandle createTaskGroup(void *userData = nullptr, uint32_t reserveSize = 0)
+ {
TaskGroup *group = XA_NEW(MemTag::Default, TaskGroup);
group->queue.reserve(reserveSize);
group->userData = userData;
@@ -3145,11 +3326,13 @@ public:
return handle;
}
- void run(TaskGroupHandle handle, Task task) {
+ void run(TaskGroupHandle handle, Task task)
+ {
m_groups[handle.value]->queue.push_back(task);
}
- void wait(TaskGroupHandle *handle) {
+ void wait(TaskGroupHandle *handle)
+ {
if (handle->value == UINT32_MAX) {
XA_DEBUG_ASSERT(false);
return;
@@ -3165,7 +3348,8 @@ public:
static uint32_t currentThreadIndex() { return 0; }
private:
- void destroyGroup(TaskGroupHandle handle) {
+ void destroyGroup(TaskGroupHandle handle)
+ {
TaskGroup *group = m_groups[handle.value];
if (group) {
group->~TaskGroup();
@@ -3174,7 +3358,8 @@ private:
}
}
- struct TaskGroup {
+ struct TaskGroup
+ {
Array<Task> queue;
void *userData;
};
@@ -3188,7 +3373,8 @@ const uint8_t TGA_TYPE_RGB = 2;
const uint8_t TGA_ORIGIN_UPPER = 0x20;
#pragma pack(push, 1)
-struct TgaHeader {
+struct TgaHeader
+{
uint8_t id_length;
uint8_t colormap_type;
uint8_t image_type;
@@ -3205,7 +3391,8 @@ struct TgaHeader {
};
#pragma pack(pop)
-static void WriteTga(const char *filename, const uint8_t *data, uint32_t width, uint32_t height) {
+static void WriteTga(const char *filename, const uint8_t *data, uint32_t width, uint32_t height)
+{
XA_DEBUG_ASSERT(sizeof(TgaHeader) == TgaHeader::Size);
FILE *f;
XA_FOPEN(f, filename, "wb");
@@ -3230,10 +3417,12 @@ static void WriteTga(const char *filename, const uint8_t *data, uint32_t width,
}
#endif
-template <typename T>
-class ThreadLocal {
+template<typename T>
+class ThreadLocal
+{
public:
- ThreadLocal() {
+ ThreadLocal()
+ {
#if XA_MULTITHREADED
const uint32_t n = std::thread::hardware_concurrency();
#else
@@ -3244,7 +3433,8 @@ public:
new (&m_array[i]) T;
}
- ~ThreadLocal() {
+ ~ThreadLocal()
+ {
#if XA_MULTITHREADED
const uint32_t n = std::thread::hardware_concurrency();
#else
@@ -3255,7 +3445,8 @@ public:
XA_FREE(m_array);
}
- T &get() const {
+ T &get() const
+ {
return m_array[TaskScheduler::currentThreadIndex()];
}
@@ -3264,10 +3455,12 @@ private:
};
// Implemented as a struct so the temporary arrays can be reused.
-struct Triangulator {
+struct Triangulator
+{
// This is doing a simple ear-clipping algorithm that skips invalid triangles. Ideally, we should
// also sort the ears by angle, start with the ones that have the smallest angle and proceed in order.
- void triangulatePolygon(ConstArrayView<Vector3> vertices, ConstArrayView<uint32_t> inputIndices, Array<uint32_t> &outputIndices) {
+ void triangulatePolygon(ConstArrayView<Vector3> vertices, ConstArrayView<uint32_t> inputIndices, Array<uint32_t> &outputIndices)
+ {
m_polygonVertices.clear();
m_polygonVertices.reserve(inputIndices.length);
outputIndices.clear();
@@ -3276,7 +3469,8 @@ struct Triangulator {
outputIndices.push_back(inputIndices[0]);
outputIndices.push_back(inputIndices[1]);
outputIndices.push_back(inputIndices[2]);
- } else {
+ }
+ else {
// Build 2D polygon projecting vertices onto normal plane.
// Faces are not necesarily planar, this is for example the case, when the face comes from filling a hole. In such cases
// it's much better to use the best fit plane.
@@ -3348,7 +3542,8 @@ struct Triangulator {
}
private:
- static bool pointInTriangle(const Vector2 &p, const Vector2 &a, const Vector2 &b, const Vector2 &c) {
+ static bool pointInTriangle(const Vector2 &p, const Vector2 &a, const Vector2 &b, const Vector2 &c)
+ {
return triangleArea(a, b, p) >= kAreaEpsilon && triangleArea(b, c, p) >= kAreaEpsilon && triangleArea(c, a, p) >= kAreaEpsilon;
}
@@ -3357,10 +3552,12 @@ private:
Array<Vector2> m_polygonPoints;
};
-class UniformGrid2 {
+class UniformGrid2
+{
public:
// indices are optional.
- void reset(ConstArrayView<Vector2> positions, ConstArrayView<uint32_t> indices = ConstArrayView<uint32_t>(), uint32_t reserveEdgeCount = 0) {
+ void reset(ConstArrayView<Vector2> positions, ConstArrayView<uint32_t> indices = ConstArrayView<uint32_t>(), uint32_t reserveEdgeCount = 0)
+ {
m_edges.clear();
if (reserveEdgeCount > 0)
m_edges.reserve(reserveEdgeCount);
@@ -3369,12 +3566,14 @@ public:
m_cellDataOffsets.clear();
}
- void append(uint32_t edge) {
+ void append(uint32_t edge)
+ {
XA_DEBUG_ASSERT(m_cellDataOffsets.isEmpty());
m_edges.push_back(edge);
}
- bool intersect(Vector2 v1, Vector2 v2, float epsilon) {
+ bool intersect(Vector2 v1, Vector2 v2, float epsilon)
+ {
const uint32_t edgeCount = m_edges.size();
bool bruteForce = edgeCount <= 20;
if (!bruteForce && m_cellDataOffsets.isEmpty())
@@ -3401,7 +3600,8 @@ public:
}
// If edges is empty, checks for intersection with all edges in the grid.
- bool intersect(float epsilon, ConstArrayView<uint32_t> edges = ConstArrayView<uint32_t>(), ConstArrayView<uint32_t> ignoreEdges = ConstArrayView<uint32_t>()) {
+ bool intersect(float epsilon, ConstArrayView<uint32_t> edges = ConstArrayView<uint32_t>(), ConstArrayView<uint32_t> ignoreEdges = ConstArrayView<uint32_t>())
+ {
bool bruteForce = m_edges.size() <= 20;
if (!bruteForce && m_cellDataOffsets.isEmpty())
bruteForce = !createGrid();
@@ -3471,7 +3671,8 @@ public:
}
#if XA_DEBUG_EXPORT_BOUNDARY_GRID
- void debugExport(const char *filename) {
+ void debugExport(const char *filename)
+ {
Array<uint8_t> image;
image.resize(m_gridWidth * m_gridHeight * 3);
for (uint32_t y = 0; y < m_gridHeight; y++) {
@@ -3493,7 +3694,8 @@ public:
#endif
private:
- bool createGrid() {
+ bool createGrid()
+ {
// Compute edge extents. Min will be the grid origin.
const uint32_t edgeCount = m_edges.size();
Extents2 edgeExtents;
@@ -3545,7 +3747,8 @@ private:
return true;
}
- void computePotentialEdges(Vector2 p1, Vector2 p2) {
+ void computePotentialEdges(Vector2 p1, Vector2 p2)
+ {
m_potentialEdges.clear();
traverse(p1, p2);
for (uint32_t j = 0; j < m_traversedCellOffsets.size(); j++) {
@@ -3563,7 +3766,8 @@ private:
}
// "A Fast Voxel Traversal Algorithm for Ray Tracing"
- void traverse(Vector2 p1, Vector2 p2) {
+ void traverse(Vector2 p1, Vector2 p2)
+ {
const Vector2 dir = p2 - p1;
const Vector2 normal = normalizeSafe(dir, Vector2(0.0f));
const int stepX = dir.x >= 0 ? 1 : -1;
@@ -3584,12 +3788,14 @@ private:
if (normal.x > kEpsilon || normal.x < -kEpsilon) {
tMaxX = (distToNextCellX * stepX) / normal.x;
tDeltaX = (m_cellSize * stepX) / normal.x;
- } else
+ }
+ else
tMaxX = tDeltaX = FLT_MAX;
if (normal.y > kEpsilon || normal.y < -kEpsilon) {
tMaxY = (distToNextCellY * stepY) / normal.y;
tDeltaY = (m_cellSize * stepY) / normal.y;
- } else
+ }
+ else
tMaxY = tDeltaY = FLT_MAX;
m_traversedCellOffsets.clear();
m_traversedCellOffsets.push_back(firstCell[0] + firstCell[1] * m_gridWidth);
@@ -3616,23 +3822,28 @@ private:
}
}
- uint32_t cellX(float x) const {
+ uint32_t cellX(float x) const
+ {
return min((uint32_t)max(0.0f, (x - m_gridOrigin.x) / m_cellSize), m_gridWidth - 1u);
}
- uint32_t cellY(float y) const {
+ uint32_t cellY(float y) const
+ {
return min((uint32_t)max(0.0f, (y - m_gridOrigin.y) / m_cellSize), m_gridHeight - 1u);
}
- Vector2 edgePosition0(uint32_t edge) const {
+ Vector2 edgePosition0(uint32_t edge) const
+ {
return m_positions[vertexAt(meshEdgeIndex0(edge))];
}
- Vector2 edgePosition1(uint32_t edge) const {
+ Vector2 edgePosition1(uint32_t edge) const
+ {
return m_positions[vertexAt(meshEdgeIndex1(edge))];
}
- uint32_t vertexAt(uint32_t index) const {
+ uint32_t vertexAt(uint32_t index) const
+ {
return m_indices.length > 0 ? m_indices[index] : index;
}
@@ -3648,13 +3859,15 @@ private:
Array<uint32_t> m_traversedCellOffsets;
};
-struct UvMeshChart {
+struct UvMeshChart
+{
Array<uint32_t> faces;
Array<uint32_t> indices;
uint32_t material;
};
-struct UvMesh {
+struct UvMesh
+{
UvMeshDecl decl;
BitArray faceIgnore;
Array<uint32_t> faceMaterials;
@@ -3664,7 +3877,8 @@ struct UvMesh {
Array<uint32_t> vertexToChartMap;
};
-struct UvMeshInstance {
+struct UvMeshInstance
+{
UvMesh *mesh;
Array<Vector2> texcoords;
};
@@ -3712,30 +3926,27 @@ struct UvMeshInstance {
* FRANCE
*/
namespace opennl {
-#define NL_NEW(T) XA_ALLOC(MemTag::OpenNL, T)
-#define NL_NEW_ARRAY(T, NB) XA_ALLOC_ARRAY(MemTag::OpenNL, T, NB)
-#define NL_RENEW_ARRAY(T, x, NB) XA_REALLOC(MemTag::OpenNL, x, T, NB)
-#define NL_DELETE(x) \
- XA_FREE(x); \
- x = nullptr
-#define NL_DELETE_ARRAY(x) \
- XA_FREE(x); \
- x = nullptr
-#define NL_CLEAR(x, T) memset(x, 0, sizeof(T));
-#define NL_CLEAR_ARRAY(T, x, NB) memset(x, 0, (size_t)(NB) * sizeof(T))
-#define NL_NEW_VECTOR(dim) XA_ALLOC_ARRAY(MemTag::OpenNL, double, dim)
-#define NL_DELETE_VECTOR(ptr) XA_FREE(ptr)
+#define NL_NEW(T) XA_ALLOC(MemTag::OpenNL, T)
+#define NL_NEW_ARRAY(T,NB) XA_ALLOC_ARRAY(MemTag::OpenNL, T, NB)
+#define NL_RENEW_ARRAY(T,x,NB) XA_REALLOC(MemTag::OpenNL, x, T, NB)
+#define NL_DELETE(x) XA_FREE(x); x = nullptr
+#define NL_DELETE_ARRAY(x) XA_FREE(x); x = nullptr
+#define NL_CLEAR(x, T) memset(x, 0, sizeof(T));
+#define NL_CLEAR_ARRAY(T,x,NB) memset(x, 0, (size_t)(NB)*sizeof(T))
+#define NL_NEW_VECTOR(dim) XA_ALLOC_ARRAY(MemTag::OpenNL, double, dim)
+#define NL_DELETE_VECTOR(ptr) XA_FREE(ptr)
struct NLMatrixStruct;
-typedef NLMatrixStruct *NLMatrix;
+typedef NLMatrixStruct * NLMatrix;
typedef void (*NLDestroyMatrixFunc)(NLMatrix M);
-typedef void (*NLMultMatrixVectorFunc)(NLMatrix M, const double *x, double *y);
+typedef void (*NLMultMatrixVectorFunc)(NLMatrix M, const double* x, double* y);
#define NL_MATRIX_SPARSE_DYNAMIC 0x1001
-#define NL_MATRIX_CRS 0x1002
-#define NL_MATRIX_OTHER 0x1006
+#define NL_MATRIX_CRS 0x1002
+#define NL_MATRIX_OTHER 0x1006
-struct NLMatrixStruct {
+struct NLMatrixStruct
+{
uint32_t m;
uint32_t n;
uint32_t type;
@@ -3745,35 +3956,39 @@ struct NLMatrixStruct {
/* Dynamic arrays for sparse row/columns */
-struct NLCoeff {
+struct NLCoeff
+{
uint32_t index;
double value;
};
-struct NLRowColumn {
+struct NLRowColumn
+{
uint32_t size;
uint32_t capacity;
- NLCoeff *coeff;
+ NLCoeff* coeff;
};
/* Compressed Row Storage */
-struct NLCRSMatrix {
+struct NLCRSMatrix
+{
uint32_t m;
uint32_t n;
uint32_t type;
NLDestroyMatrixFunc destroy_func;
NLMultMatrixVectorFunc mult_func;
- double *val;
- uint32_t *rowptr;
- uint32_t *colind;
+ double* val;
+ uint32_t* rowptr;
+ uint32_t* colind;
uint32_t nslices;
- uint32_t *sliceptr;
+ uint32_t* sliceptr;
};
/* SparseMatrix data structure */
-struct NLSparseMatrix {
+struct NLSparseMatrix
+{
uint32_t m;
uint32_t n;
uint32_t type;
@@ -3781,23 +3996,25 @@ struct NLSparseMatrix {
NLMultMatrixVectorFunc mult_func;
uint32_t diag_size;
uint32_t diag_capacity;
- NLRowColumn *row;
- NLRowColumn *column;
- double *diag;
+ NLRowColumn* row;
+ NLRowColumn* column;
+ double* diag;
uint32_t row_capacity;
uint32_t column_capacity;
};
/* NLContext data structure */
-struct NLBufferBinding {
- void *base_address;
+struct NLBufferBinding
+{
+ void* base_address;
uint32_t stride;
};
-#define NL_BUFFER_ITEM(B, i) *(double *)((void *)((char *)((B).base_address) + ((i) * (B).stride)))
+#define NL_BUFFER_ITEM(B,i) *(double*)((void*)((char*)((B).base_address)+((i)*(B).stride)))
-struct NLContext {
+struct NLContext
+{
NLBufferBinding *variable_buffer;
double *variable_value;
bool *variable_is_locked;
@@ -3821,30 +4038,35 @@ struct NLContext {
double error;
};
-static void nlDeleteMatrix(NLMatrix M) {
+static void nlDeleteMatrix(NLMatrix M)
+{
if (!M)
return;
M->destroy_func(M);
NL_DELETE(M);
}
-static void nlMultMatrixVector(NLMatrix M, const double *x, double *y) {
+static void nlMultMatrixVector(NLMatrix M, const double* x, double* y)
+{
M->mult_func(M, x, y);
}
-static void nlRowColumnConstruct(NLRowColumn *c) {
+static void nlRowColumnConstruct(NLRowColumn* c)
+{
c->size = 0;
c->capacity = 0;
c->coeff = nullptr;
}
-static void nlRowColumnDestroy(NLRowColumn *c) {
+static void nlRowColumnDestroy(NLRowColumn* c)
+{
NL_DELETE_ARRAY(c->coeff);
c->size = 0;
c->capacity = 0;
}
-static void nlRowColumnGrow(NLRowColumn *c) {
+static void nlRowColumnGrow(NLRowColumn* c)
+{
if (c->capacity != 0) {
c->capacity = 2 * c->capacity;
c->coeff = NL_RENEW_ARRAY(NLCoeff, c->coeff, c->capacity);
@@ -3855,7 +4077,8 @@ static void nlRowColumnGrow(NLRowColumn *c) {
}
}
-static void nlRowColumnAdd(NLRowColumn *c, uint32_t index, double value) {
+static void nlRowColumnAdd(NLRowColumn* c, uint32_t index, double value)
+{
for (uint32_t i = 0; i < c->size; i++) {
if (c->coeff[i].index == index) {
c->coeff[i].value += value;
@@ -3870,7 +4093,8 @@ static void nlRowColumnAdd(NLRowColumn *c, uint32_t index, double value) {
}
/* Does not check whether the index already exists */
-static void nlRowColumnAppend(NLRowColumn *c, uint32_t index, double value) {
+static void nlRowColumnAppend(NLRowColumn* c, uint32_t index, double value)
+{
if (c->size == c->capacity)
nlRowColumnGrow(c);
c->coeff[c->size].index = index;
@@ -3878,27 +4102,32 @@ static void nlRowColumnAppend(NLRowColumn *c, uint32_t index, double value) {
c->size++;
}
-static void nlRowColumnZero(NLRowColumn *c) {
+static void nlRowColumnZero(NLRowColumn* c)
+{
c->size = 0;
}
-static void nlRowColumnClear(NLRowColumn *c) {
+static void nlRowColumnClear(NLRowColumn* c)
+{
c->size = 0;
c->capacity = 0;
NL_DELETE_ARRAY(c->coeff);
}
-static int nlCoeffCompare(const void *p1, const void *p2) {
- return (((NLCoeff *)(p2))->index < ((NLCoeff *)(p1))->index);
+static int nlCoeffCompare(const void* p1, const void* p2)
+{
+ return (((NLCoeff*)(p2))->index < ((NLCoeff*)(p1))->index);
}
-static void nlRowColumnSort(NLRowColumn *c) {
+static void nlRowColumnSort(NLRowColumn* c)
+{
qsort(c->coeff, c->size, sizeof(NLCoeff), nlCoeffCompare);
}
/* CRSMatrix data structure */
-static void nlCRSMatrixDestroy(NLCRSMatrix *M) {
+static void nlCRSMatrixDestroy(NLCRSMatrix* M)
+{
NL_DELETE_ARRAY(M->val);
NL_DELETE_ARRAY(M->rowptr);
NL_DELETE_ARRAY(M->colind);
@@ -3908,7 +4137,8 @@ static void nlCRSMatrixDestroy(NLCRSMatrix *M) {
M->nslices = 0;
}
-static void nlCRSMatrixMultSlice(NLCRSMatrix *M, const double *x, double *y, uint32_t Ibegin, uint32_t Iend) {
+static void nlCRSMatrixMultSlice(NLCRSMatrix* M, const double* x, double* y, uint32_t Ibegin, uint32_t Iend)
+{
for (uint32_t i = Ibegin; i < Iend; ++i) {
double sum = 0.0;
for (uint32_t j = M->rowptr[i]; j < M->rowptr[i + 1]; ++j)
@@ -3917,13 +4147,15 @@ static void nlCRSMatrixMultSlice(NLCRSMatrix *M, const double *x, double *y, uin
}
}
-static void nlCRSMatrixMult(NLCRSMatrix *M, const double *x, double *y) {
+static void nlCRSMatrixMult(NLCRSMatrix* M, const double* x, double* y)
+{
int nslices = (int)(M->nslices);
for (int slice = 0; slice < nslices; ++slice)
nlCRSMatrixMultSlice(M, x, y, M->sliceptr[slice], M->sliceptr[slice + 1]);
}
-static void nlCRSMatrixConstruct(NLCRSMatrix *M, uint32_t m, uint32_t n, uint32_t nnz, uint32_t nslices) {
+static void nlCRSMatrixConstruct(NLCRSMatrix* M, uint32_t m, uint32_t n, uint32_t nnz, uint32_t nslices)
+{
M->m = m;
M->n = n;
M->type = NL_MATRIX_CRS;
@@ -3942,19 +4174,22 @@ static void nlCRSMatrixConstruct(NLCRSMatrix *M, uint32_t m, uint32_t n, uint32_
/* SparseMatrix data structure */
-static void nlSparseMatrixDestroyRowColumns(NLSparseMatrix *M) {
+static void nlSparseMatrixDestroyRowColumns(NLSparseMatrix* M)
+{
for (uint32_t i = 0; i < M->m; i++)
nlRowColumnDestroy(&(M->row[i]));
NL_DELETE_ARRAY(M->row);
}
-static void nlSparseMatrixDestroy(NLSparseMatrix *M) {
+static void nlSparseMatrixDestroy(NLSparseMatrix* M)
+{
XA_DEBUG_ASSERT(M->type == NL_MATRIX_SPARSE_DYNAMIC);
nlSparseMatrixDestroyRowColumns(M);
NL_DELETE_ARRAY(M->diag);
}
-static void nlSparseMatrixAdd(NLSparseMatrix *M, uint32_t i, uint32_t j, double value) {
+static void nlSparseMatrixAdd(NLSparseMatrix* M, uint32_t i, uint32_t j, double value)
+{
XA_DEBUG_ASSERT(i >= 0 && i <= M->m - 1);
XA_DEBUG_ASSERT(j >= 0 && j <= M->n - 1);
if (i == j)
@@ -3963,21 +4198,24 @@ static void nlSparseMatrixAdd(NLSparseMatrix *M, uint32_t i, uint32_t j, double
}
/* Returns the number of non-zero coefficients */
-static uint32_t nlSparseMatrixNNZ(NLSparseMatrix *M) {
+static uint32_t nlSparseMatrixNNZ(NLSparseMatrix* M)
+{
uint32_t nnz = 0;
for (uint32_t i = 0; i < M->m; i++)
nnz += M->row[i].size;
return nnz;
}
-static void nlSparseMatrixSort(NLSparseMatrix *M) {
+static void nlSparseMatrixSort(NLSparseMatrix* M)
+{
for (uint32_t i = 0; i < M->m; i++)
nlRowColumnSort(&(M->row[i]));
}
/* SparseMatrix x Vector routines, internal helper routines */
-static void nlSparseMatrix_mult_rows(NLSparseMatrix *A, const double *x, double *y) {
+static void nlSparseMatrix_mult_rows(NLSparseMatrix* A, const double* x, double* y)
+{
/*
* Note: OpenMP does not like unsigned ints
* (causes some floating point exceptions),
@@ -3985,8 +4223,8 @@ static void nlSparseMatrix_mult_rows(NLSparseMatrix *A, const double *x, double
* indices.
*/
int m = (int)(A->m);
- NLCoeff *c = nullptr;
- NLRowColumn *Ri = nullptr;
+ NLCoeff* c = nullptr;
+ NLRowColumn* Ri = nullptr;
for (int i = 0; i < m; i++) {
Ri = &(A->row[i]);
y[i] = 0;
@@ -3997,12 +4235,14 @@ static void nlSparseMatrix_mult_rows(NLSparseMatrix *A, const double *x, double
}
}
-static void nlSparseMatrixMult(NLSparseMatrix *A, const double *x, double *y) {
+static void nlSparseMatrixMult(NLSparseMatrix* A, const double* x, double* y)
+{
XA_DEBUG_ASSERT(A->type == NL_MATRIX_SPARSE_DYNAMIC);
nlSparseMatrix_mult_rows(A, x, y);
}
-static void nlSparseMatrixConstruct(NLSparseMatrix *M, uint32_t m, uint32_t n) {
+static void nlSparseMatrixConstruct(NLSparseMatrix* M, uint32_t m, uint32_t n)
+{
M->m = m;
M->n = n;
M->type = NL_MATRIX_SPARSE_DYNAMIC;
@@ -4022,23 +4262,24 @@ static void nlSparseMatrixConstruct(NLSparseMatrix *M, uint32_t m, uint32_t n) {
NL_CLEAR_ARRAY(double, M->diag, M->diag_size);
}
-static NLMatrix nlCRSMatrixNewFromSparseMatrix(NLSparseMatrix *M) {
+static NLMatrix nlCRSMatrixNewFromSparseMatrix(NLSparseMatrix* M)
+{
uint32_t nnz = nlSparseMatrixNNZ(M);
uint32_t nslices = 8; /* TODO: get number of cores */
uint32_t slice, cur_bound, cur_NNZ, cur_row;
uint32_t k;
uint32_t slice_size = nnz / nslices;
- NLCRSMatrix *CRS = NL_NEW(NLCRSMatrix);
+ NLCRSMatrix* CRS = NL_NEW(NLCRSMatrix);
NL_CLEAR(CRS, NLCRSMatrix);
nlCRSMatrixConstruct(CRS, M->m, M->n, nnz, nslices);
nlSparseMatrixSort(M);
/* Convert matrix to CRS format */
k = 0;
for (uint32_t i = 0; i < M->m; ++i) {
- NLRowColumn *Ri = &(M->row[i]);
+ NLRowColumn* Ri = &(M->row[i]);
CRS->rowptr[i] = k;
for (uint32_t ij = 0; ij < Ri->size; ij++) {
- NLCoeff *c = &(Ri->coeff[ij]);
+ NLCoeff* c = &(Ri->coeff[ij]);
CRS->val[k] = c->value;
CRS->colind[k] = c->index;
++k;
@@ -4053,8 +4294,8 @@ static NLMatrix nlCRSMatrixNewFromSparseMatrix(NLSparseMatrix *M) {
CRS->sliceptr[0] = 0;
for (slice = 1; slice < nslices; ++slice) {
while (cur_NNZ < cur_bound && cur_row < M->m) {
- ++cur_row;
cur_NNZ += CRS->rowptr[cur_row + 1] - CRS->rowptr[cur_row];
+ ++cur_row;
}
CRS->sliceptr[slice] = cur_row;
cur_bound += slice_size;
@@ -4064,17 +4305,19 @@ static NLMatrix nlCRSMatrixNewFromSparseMatrix(NLSparseMatrix *M) {
return (NLMatrix)CRS;
}
-static void nlMatrixCompress(NLMatrix *M) {
+static void nlMatrixCompress(NLMatrix* M)
+{
NLMatrix CRS = nullptr;
if ((*M)->type != NL_MATRIX_SPARSE_DYNAMIC)
return;
- CRS = nlCRSMatrixNewFromSparseMatrix((NLSparseMatrix *)*M);
+ CRS = nlCRSMatrixNewFromSparseMatrix((NLSparseMatrix*)*M);
nlDeleteMatrix(*M);
*M = CRS;
}
-static NLContext *nlNewContext() {
- NLContext *result = NL_NEW(NLContext);
+static NLContext *nlNewContext()
+{
+ NLContext* result = NL_NEW(NLContext);
NL_CLEAR(result, NLContext);
result->max_iterations = 100;
result->threshold = 1e-6;
@@ -4083,7 +4326,8 @@ static NLContext *nlNewContext() {
return result;
}
-static void nlDeleteContext(NLContext *context) {
+static void nlDeleteContext(NLContext *context)
+{
nlDeleteMatrix(context->M);
context->M = nullptr;
nlDeleteMatrix(context->P);
@@ -4101,19 +4345,22 @@ static void nlDeleteContext(NLContext *context) {
NL_DELETE(context);
}
-static double ddot(int n, const double *x, const double *y) {
+static double ddot(int n, const double *x, const double *y)
+{
double sum = 0.0;
for (int i = 0; i < n; i++)
sum += x[i] * y[i];
return sum;
}
-static void daxpy(int n, double a, const double *x, double *y) {
+static void daxpy(int n, double a, const double *x, double *y)
+{
for (int i = 0; i < n; i++)
y[i] = a * x[i] + y[i];
}
-static void dscal(int n, double a, double *x) {
+static void dscal(int n, double a, double *x)
+{
for (int i = 0; i < n; i++)
x[i] *= a;
}
@@ -4136,16 +4383,17 @@ static void dscal(int n, double a, double *x) {
* versions of matrix x vector product (CPU/GPU, sparse/dense ...)
*/
-static uint32_t nlSolveSystem_PRE_CG(NLMatrix M, NLMatrix P, double *b, double *x, double eps, uint32_t max_iter, double *sq_bnorm, double *sq_rnorm) {
- int N = (int)M->n;
- double *r = NL_NEW_VECTOR(N);
- double *d = NL_NEW_VECTOR(N);
- double *h = NL_NEW_VECTOR(N);
+static uint32_t nlSolveSystem_PRE_CG(NLMatrix M, NLMatrix P, double* b, double* x, double eps, uint32_t max_iter, double *sq_bnorm, double *sq_rnorm)
+{
+ int N = (int)M->n;
+ double* r = NL_NEW_VECTOR(N);
+ double* d = NL_NEW_VECTOR(N);
+ double* h = NL_NEW_VECTOR(N);
double *Ad = h;
uint32_t its = 0;
double rh, alpha, beta;
double b_square = ddot(N, b, b);
- double err = eps * eps * b_square;
+ double err = eps * eps*b_square;
double curr_err;
nlMultMatrixVector(M, x, r);
daxpy(N, -1., b, r);
@@ -4175,12 +4423,13 @@ static uint32_t nlSolveSystem_PRE_CG(NLMatrix M, NLMatrix P, double *b, double *
return its;
}
-static uint32_t nlSolveSystemIterative(NLContext *context, NLMatrix M, NLMatrix P, double *b_in, double *x_in, double eps, uint32_t max_iter) {
+static uint32_t nlSolveSystemIterative(NLContext *context, NLMatrix M, NLMatrix P, double* b_in, double* x_in, double eps, uint32_t max_iter)
+{
uint32_t result = 0;
double rnorm = 0.0;
double bnorm = 0.0;
- double *b = b_in;
- double *x = x_in;
+ double* b = b_in;
+ double* x = x_in;
XA_DEBUG_ASSERT(M->m == M->n);
double sq_bnorm, sq_rnorm;
result = nlSolveSystem_PRE_CG(M, P, b, x, eps, max_iter, &sq_bnorm, &sq_rnorm);
@@ -4195,9 +4444,10 @@ static uint32_t nlSolveSystemIterative(NLContext *context, NLMatrix M, NLMatrix
return result;
}
-static bool nlSolveIterative(NLContext *context) {
- double *b = context->b;
- double *x = context->x;
+static bool nlSolveIterative(NLContext *context)
+{
+ double* b = context->b;
+ double* x = context->x;
uint32_t n = context->n;
NLMatrix M = context->M;
NLMatrix P = context->P;
@@ -4209,30 +4459,34 @@ static bool nlSolveIterative(NLContext *context) {
return true;
}
-struct NLJacobiPreconditioner {
+struct NLJacobiPreconditioner
+{
uint32_t m;
uint32_t n;
uint32_t type;
NLDestroyMatrixFunc destroy_func;
NLMultMatrixVectorFunc mult_func;
- double *diag_inv;
+ double* diag_inv;
};
-static void nlJacobiPreconditionerDestroy(NLJacobiPreconditioner *M) {
+static void nlJacobiPreconditionerDestroy(NLJacobiPreconditioner* M)
+{
NL_DELETE_ARRAY(M->diag_inv);
}
-static void nlJacobiPreconditionerMult(NLJacobiPreconditioner *M, const double *x, double *y) {
+static void nlJacobiPreconditionerMult(NLJacobiPreconditioner* M, const double* x, double* y)
+{
for (uint32_t i = 0; i < M->n; ++i)
y[i] = x[i] * M->diag_inv[i];
}
-static NLMatrix nlNewJacobiPreconditioner(NLMatrix M_in) {
- NLSparseMatrix *M = nullptr;
- NLJacobiPreconditioner *result = nullptr;
+static NLMatrix nlNewJacobiPreconditioner(NLMatrix M_in)
+{
+ NLSparseMatrix* M = nullptr;
+ NLJacobiPreconditioner* result = nullptr;
XA_DEBUG_ASSERT(M_in->type == NL_MATRIX_SPARSE_DYNAMIC);
XA_DEBUG_ASSERT(M_in->m == M_in->n);
- M = (NLSparseMatrix *)M_in;
+ M = (NLSparseMatrix*)M_in;
result = NL_NEW(NLJacobiPreconditioner);
NL_CLEAR(result, NLJacobiPreconditioner);
result->m = M->m;
@@ -4250,7 +4504,8 @@ static NLMatrix nlNewJacobiPreconditioner(NLMatrix M_in) {
#define NL_NB_VARIABLES 0x101
#define NL_MAX_ITERATIONS 0x103
-static void nlSolverParameteri(NLContext *context, uint32_t pname, int param) {
+static void nlSolverParameteri(NLContext *context, uint32_t pname, int param)
+{
if (pname == NL_NB_VARIABLES) {
XA_DEBUG_ASSERT(param > 0);
context->nb_variables = (uint32_t)param;
@@ -4261,22 +4516,26 @@ static void nlSolverParameteri(NLContext *context, uint32_t pname, int param) {
}
}
-static void nlSetVariable(NLContext *context, uint32_t index, double value) {
+static void nlSetVariable(NLContext *context, uint32_t index, double value)
+{
XA_DEBUG_ASSERT(index >= 0 && index <= context->nb_variables - 1);
NL_BUFFER_ITEM(context->variable_buffer[0], index) = value;
}
-static double nlGetVariable(NLContext *context, uint32_t index) {
+static double nlGetVariable(NLContext *context, uint32_t index)
+{
XA_DEBUG_ASSERT(index >= 0 && index <= context->nb_variables - 1);
return NL_BUFFER_ITEM(context->variable_buffer[0], index);
}
-static void nlLockVariable(NLContext *context, uint32_t index) {
+static void nlLockVariable(NLContext *context, uint32_t index)
+{
XA_DEBUG_ASSERT(index >= 0 && index <= context->nb_variables - 1);
context->variable_is_locked[index] = true;
}
-static void nlVariablesToVector(NLContext *context) {
+static void nlVariablesToVector(NLContext *context)
+{
uint32_t n = context->n;
XA_DEBUG_ASSERT(context->x);
for (uint32_t k = 0; k < context->nb_systems; ++k) {
@@ -4291,7 +4550,8 @@ static void nlVariablesToVector(NLContext *context) {
}
}
-static void nlVectorToVariables(NLContext *context) {
+static void nlVectorToVariables(NLContext *context)
+{
uint32_t n = context->n;
XA_DEBUG_ASSERT(context->x);
for (uint32_t k = 0; k < context->nb_systems; ++k) {
@@ -4306,7 +4566,8 @@ static void nlVectorToVariables(NLContext *context) {
}
}
-static void nlCoefficient(NLContext *context, uint32_t index, double value) {
+static void nlCoefficient(NLContext *context, uint32_t index, double value)
+{
XA_DEBUG_ASSERT(index >= 0 && index <= context->nb_variables - 1);
if (context->variable_is_locked[index]) {
/*
@@ -4323,11 +4584,12 @@ static void nlCoefficient(NLContext *context, uint32_t index, double value) {
}
}
-#define NL_SYSTEM 0x0
-#define NL_MATRIX 0x1
-#define NL_ROW 0x2
+#define NL_SYSTEM 0x0
+#define NL_MATRIX 0x1
+#define NL_ROW 0x2
-static void nlBegin(NLContext *context, uint32_t prim) {
+static void nlBegin(NLContext *context, uint32_t prim)
+{
if (prim == NL_SYSTEM) {
XA_DEBUG_ASSERT(context->nb_variables > 0);
context->variable_buffer = NL_NEW_ARRAY(NLBufferBinding, context->nb_systems);
@@ -4336,8 +4598,8 @@ static void nlBegin(NLContext *context, uint32_t prim) {
NL_CLEAR_ARRAY(double, context->variable_value, context->nb_variables * context->nb_systems);
for (uint32_t k = 0; k < context->nb_systems; ++k) {
context->variable_buffer[k].base_address =
- context->variable_value +
- k * context->nb_variables;
+ context->variable_value +
+ k * context->nb_variables;
context->variable_buffer[k].stride = sizeof(double);
}
context->variable_is_locked = NL_NEW_ARRAY(bool, context->nb_variables);
@@ -4360,11 +4622,11 @@ static void nlBegin(NLContext *context, uint32_t prim) {
context->max_iterations = n * 5;
context->M = (NLMatrix)(NL_NEW(NLSparseMatrix));
NL_CLEAR(context->M, NLSparseMatrix);
- nlSparseMatrixConstruct((NLSparseMatrix *)(context->M), n, n);
- context->x = NL_NEW_ARRAY(double, n * context->nb_systems);
- NL_CLEAR_ARRAY(double, context->x, n * context->nb_systems);
- context->b = NL_NEW_ARRAY(double, n * context->nb_systems);
- NL_CLEAR_ARRAY(double, context->b, n * context->nb_systems);
+ nlSparseMatrixConstruct((NLSparseMatrix*)(context->M), n, n);
+ context->x = NL_NEW_ARRAY(double, n*context->nb_systems);
+ NL_CLEAR_ARRAY(double, context->x, n*context->nb_systems);
+ context->b = NL_NEW_ARRAY(double, n*context->nb_systems);
+ NL_CLEAR_ARRAY(double, context->b, n*context->nb_systems);
nlVariablesToVector(context);
nlRowColumnConstruct(&context->af);
nlRowColumnConstruct(&context->al);
@@ -4375,15 +4637,16 @@ static void nlBegin(NLContext *context, uint32_t prim) {
}
}
-static void nlEnd(NLContext *context, uint32_t prim) {
+static void nlEnd(NLContext *context, uint32_t prim)
+{
if (prim == NL_MATRIX) {
nlRowColumnClear(&context->af);
nlRowColumnClear(&context->al);
} else if (prim == NL_ROW) {
- NLRowColumn *af = &context->af;
- NLRowColumn *al = &context->al;
- NLSparseMatrix *M = (NLSparseMatrix *)context->M;
- double *b = context->b;
+ NLRowColumn* af = &context->af;
+ NLRowColumn* al = &context->al;
+ NLSparseMatrix* M = (NLSparseMatrix*)context->M;
+ double* b = context->b;
uint32_t nf = af->size;
uint32_t nl = al->size;
uint32_t n = context->n;
@@ -4404,13 +4667,14 @@ static void nlEnd(NLContext *context, uint32_t prim) {
S += al->coeff[jj].value * NL_BUFFER_ITEM(context->variable_buffer[k], j);
}
for (uint32_t jj = 0; jj < nf; jj++)
- b[k * n + af->coeff[jj].index] -= af->coeff[jj].value * S;
+ b[k*n + af->coeff[jj].index] -= af->coeff[jj].value * S;
}
context->current_row++;
}
}
-static bool nlSolve(NLContext *context) {
+static bool nlSolve(NLContext *context)
+{
nlDeleteMatrix(context->P);
context->P = nlNewJacobiPreconditioner(context->M);
nlMatrixCompress(&context->M);
@@ -4421,9 +4685,11 @@ static bool nlSolve(NLContext *context) {
} // namespace opennl
namespace raster {
-class ClippedTriangle {
+class ClippedTriangle
+{
public:
- ClippedTriangle(const Vector2 &a, const Vector2 &b, const Vector2 &c) {
+ ClippedTriangle(const Vector2 &a, const Vector2 &b, const Vector2 &c)
+ {
m_numVertices = 3;
m_activeVertexBuffer = 0;
m_verticesA[0] = a;
@@ -4434,20 +4700,20 @@ public:
m_area = 0;
}
- void clipHorizontalPlane(float offset, float clipdirection) {
- Vector2 *v = m_vertexBuffers[m_activeVertexBuffer];
+ void clipHorizontalPlane(float offset, float clipdirection)
+ {
+ Vector2 *v = m_vertexBuffers[m_activeVertexBuffer];
m_activeVertexBuffer ^= 1;
Vector2 *v2 = m_vertexBuffers[m_activeVertexBuffer];
v[m_numVertices] = v[0];
- float dy2, dy1 = offset - v[0].y;
- int dy2in, dy1in = clipdirection * dy1 >= 0;
- uint32_t p = 0;
+ float dy2, dy1 = offset - v[0].y;
+ int dy2in, dy1in = clipdirection * dy1 >= 0;
+ uint32_t p = 0;
for (uint32_t k = 0; k < m_numVertices; k++) {
- dy2 = offset - v[k + 1].y;
+ dy2 = offset - v[k + 1].y;
dy2in = clipdirection * dy2 >= 0;
- if (dy1in)
- v2[p++] = v[k];
- if (dy1in + dy2in == 1) { // not both in/out
+ if (dy1in) v2[p++] = v[k];
+ if ( dy1in + dy2in == 1 ) { // not both in/out
float dx = v[k + 1].x - v[k].x;
float dy = v[k + 1].y - v[k].y;
v2[p++] = Vector2(v[k].x + dy1 * (dx / dy), offset);
@@ -4458,20 +4724,20 @@ public:
m_numVertices = p;
}
- void clipVerticalPlane(float offset, float clipdirection) {
- Vector2 *v = m_vertexBuffers[m_activeVertexBuffer];
+ void clipVerticalPlane(float offset, float clipdirection)
+ {
+ Vector2 *v = m_vertexBuffers[m_activeVertexBuffer];
m_activeVertexBuffer ^= 1;
Vector2 *v2 = m_vertexBuffers[m_activeVertexBuffer];
v[m_numVertices] = v[0];
- float dx2, dx1 = offset - v[0].x;
- int dx2in, dx1in = clipdirection * dx1 >= 0;
- uint32_t p = 0;
+ float dx2, dx1 = offset - v[0].x;
+ int dx2in, dx1in = clipdirection * dx1 >= 0;
+ uint32_t p = 0;
for (uint32_t k = 0; k < m_numVertices; k++) {
dx2 = offset - v[k + 1].x;
dx2in = clipdirection * dx2 >= 0;
- if (dx1in)
- v2[p++] = v[k];
- if (dx1in + dx2in == 1) { // not both in/out
+ if (dx1in) v2[p++] = v[k];
+ if ( dx1in + dx2in == 1 ) { // not both in/out
float dx = v[k + 1].x - v[k].x;
float dy = v[k + 1].y - v[k].y;
v2[p++] = Vector2(offset, v[k].y + dx1 * (dy / dx));
@@ -4482,8 +4748,9 @@ public:
m_numVertices = p;
}
- void computeArea() {
- Vector2 *v = m_vertexBuffers[m_activeVertexBuffer];
+ void computeArea()
+ {
+ Vector2 *v = m_vertexBuffers[m_activeVertexBuffer];
v[m_numVertices] = v[0];
m_area = 0;
float centroidx = 0, centroidy = 0;
@@ -4497,7 +4764,8 @@ public:
m_area = 0.5f * fabsf(m_area);
}
- void clipAABox(float x0, float y0, float x1, float y1) {
+ void clipAABox(float x0, float y0, float x1, float y1)
+ {
clipVerticalPlane(x0, -1);
clipHorizontalPlane(y0, -1);
clipVerticalPlane(x1, 1);
@@ -4505,7 +4773,8 @@ public:
computeArea();
}
- float area() const {
+ float area() const
+ {
return m_area;
}
@@ -4522,9 +4791,10 @@ private:
typedef bool (*SamplingCallback)(void *param, int x, int y);
/// A triangle for rasterization.
-struct Triangle {
- Triangle(const Vector2 &_v0, const Vector2 &_v1, const Vector2 &_v2) :
- v1(_v0), v2(_v2), v3(_v1), n1(0.0f), n2(0.0f), n3(0.0f) {
+struct Triangle
+{
+ Triangle(const Vector2 &_v0, const Vector2 &_v1, const Vector2 &_v2) : v1(_v0), v2(_v2), v3(_v1), n1(0.0f), n2(0.0f), n3(0.0f)
+ {
// make sure every triangle is front facing.
flipBackface();
// Compute deltas.
@@ -4532,7 +4802,8 @@ struct Triangle {
computeUnitInwardNormals();
}
- bool isValid() {
+ bool isValid()
+ {
const Vector2 e0 = v3 - v1;
const Vector2 e1 = v2 - v1;
const float area = e0.y * e1.x - e1.y * e0.x;
@@ -4540,17 +4811,18 @@ struct Triangle {
}
// extents has to be multiple of BK_SIZE!!
- bool drawAA(const Vector2 &extents, SamplingCallback cb, void *param) {
- const float PX_INSIDE = 1.0f / sqrtf(2.0f);
- const float PX_OUTSIDE = -1.0f / sqrtf(2.0f);
+ bool drawAA(const Vector2 &extents, SamplingCallback cb, void *param)
+ {
+ const float PX_INSIDE = 1.0f/sqrtf(2.0f);
+ const float PX_OUTSIDE = -1.0f/sqrtf(2.0f);
const float BK_SIZE = 8;
- const float BK_INSIDE = sqrtf(BK_SIZE * BK_SIZE / 2.0f);
- const float BK_OUTSIDE = -sqrtf(BK_SIZE * BK_SIZE / 2.0f);
+ const float BK_INSIDE = sqrtf(BK_SIZE*BK_SIZE/2.0f);
+ const float BK_OUTSIDE = -sqrtf(BK_SIZE*BK_SIZE/2.0f);
// Bounding rectangle
float minx = floorf(max(min3(v1.x, v2.x, v3.x), 0.0f));
float miny = floorf(max(min3(v1.y, v2.y, v3.y), 0.0f));
- float maxx = ceilf(min(max3(v1.x, v2.x, v3.x), extents.x - 1.0f));
- float maxy = ceilf(min(max3(v1.y, v2.y, v3.y), extents.y - 1.0f));
+ float maxx = ceilf( min(max3(v1.x, v2.x, v3.x), extents.x - 1.0f));
+ float maxy = ceilf( min(max3(v1.y, v2.y, v3.y), extents.y - 1.0f));
// There's no reason to align the blocks to the viewport, instead we align them to the origin of the triangle bounds.
minx = floorf(minx);
miny = floorf(miny);
@@ -4575,10 +4847,9 @@ struct Triangle {
float bC = C2 + n2.x * xc + n2.y * yc;
float cC = C3 + n3.x * xc + n3.y * yc;
// Skip block when outside an edge
- if ((aC <= BK_OUTSIDE) || (bC <= BK_OUTSIDE) || (cC <= BK_OUTSIDE))
- continue;
+ if ( (aC <= BK_OUTSIDE) || (bC <= BK_OUTSIDE) || (cC <= BK_OUTSIDE) ) continue;
// Accept whole block when totally covered
- if ((aC >= BK_INSIDE) && (bC >= BK_INSIDE) && (cC >= BK_INSIDE)) {
+ if ( (aC >= BK_INSIDE) && (bC >= BK_INSIDE) && (cC >= BK_INSIDE) ) {
for (float y = y0; y < y0 + BK_SIZE; y++) {
for (float x = x0; x < x0 + BK_SIZE; x++) {
if (!cb(param, (int)x, (int)y))
@@ -4621,9 +4892,10 @@ struct Triangle {
}
private:
- void flipBackface() {
+ void flipBackface()
+ {
// check if triangle is backfacing, if so, swap two vertices
- if (((v3.x - v1.x) * (v2.y - v1.y) - (v3.y - v1.y) * (v2.x - v1.x)) < 0) {
+ if ( ((v3.x - v1.x) * (v2.y - v1.y) - (v3.y - v1.y) * (v2.x - v1.x)) < 0 ) {
Vector2 hv = v1;
v1 = v2;
v2 = hv; // swap pos
@@ -4631,7 +4903,8 @@ private:
}
// compute unit inward normals for each edge.
- void computeUnitInwardNormals() {
+ void computeUnitInwardNormals()
+ {
n1 = v1 - v2;
n1 = Vector2(-n1.y, n1.x);
n1 = n1 * (1.0f / sqrtf(dot(n1, n1)));
@@ -4649,7 +4922,8 @@ private:
};
// Process the given triangle. Returns false if rasterization was interrupted by the callback.
-static bool drawTriangle(const Vector2 &extents, const Vector2 v[3], SamplingCallback cb, void *param) {
+static bool drawTriangle(const Vector2 &extents, const Vector2 v[3], SamplingCallback cb, void *param)
+{
Triangle tri(v[0], v[1], v[2]);
// @@ It would be nice to have a conservative drawing mode that enlarges the triangle extents by one texel and is able to handle degenerate triangles.
// @@ Maybe the simplest thing to do would be raster triangle edges.
@@ -4664,19 +4938,22 @@ namespace segment {
// - Insertion is o(n)
// - Smallest element goes at the end, so that popping it is o(1).
-struct CostQueue {
- CostQueue(uint32_t size = UINT32_MAX) :
- m_maxSize(size), m_pairs(MemTag::SegmentAtlasChartCandidates) {}
+struct CostQueue
+{
+ CostQueue(uint32_t size = UINT32_MAX) : m_maxSize(size), m_pairs(MemTag::SegmentAtlasChartCandidates) {}
- float peekCost() const {
+ float peekCost() const
+ {
return m_pairs.back().cost;
}
- uint32_t peekFace() const {
+ uint32_t peekFace() const
+ {
return m_pairs.back().face;
}
- void push(float cost, uint32_t face) {
+ void push(float cost, uint32_t face)
+ {
const Pair p = { cost, face };
if (m_pairs.isEmpty() || cost < peekCost())
m_pairs.push_back(p);
@@ -4693,25 +4970,29 @@ struct CostQueue {
}
}
- uint32_t pop() {
+ uint32_t pop()
+ {
XA_DEBUG_ASSERT(!m_pairs.isEmpty());
uint32_t f = m_pairs.back().face;
m_pairs.pop_back();
return f;
}
- XA_INLINE void clear() {
+ XA_INLINE void clear()
+ {
m_pairs.clear();
}
- XA_INLINE uint32_t count() const {
+ XA_INLINE uint32_t count() const
+ {
return m_pairs.size();
}
private:
const uint32_t m_maxSize;
- struct Pair {
+ struct Pair
+ {
float cost;
uint32_t face;
};
@@ -4719,7 +5000,8 @@ private:
Array<Pair> m_pairs;
};
-struct AtlasData {
+struct AtlasData
+{
ChartOptions options;
const Mesh *mesh = nullptr;
Array<float> edgeDihedralAngles;
@@ -4729,10 +5011,10 @@ struct AtlasData {
Array<Vector3> faceNormals;
BitArray isFaceInChart;
- AtlasData() :
- edgeDihedralAngles(MemTag::SegmentAtlasMeshData), edgeLengths(MemTag::SegmentAtlasMeshData), faceAreas(MemTag::SegmentAtlasMeshData), faceNormals(MemTag::SegmentAtlasMeshData) {}
+ AtlasData() : edgeDihedralAngles(MemTag::SegmentAtlasMeshData), edgeLengths(MemTag::SegmentAtlasMeshData), faceAreas(MemTag::SegmentAtlasMeshData), faceNormals(MemTag::SegmentAtlasMeshData) {}
- void compute() {
+ void compute()
+ {
const uint32_t faceCount = mesh->faceCount();
const uint32_t edgeCount = mesh->edgeCount();
edgeDihedralAngles.resize(edgeCount);
@@ -4773,18 +5055,20 @@ struct AtlasData {
};
// If MeshDecl::vertexUvData is set on input meshes, find charts by floodfilling faces in world/model space without crossing UV seams.
-struct OriginalUvCharts {
- OriginalUvCharts(AtlasData &data) :
- m_data(data) {}
+struct OriginalUvCharts
+{
+ OriginalUvCharts(AtlasData &data) : m_data(data) {}
uint32_t chartCount() const { return m_charts.size(); }
const Basis &chartBasis(uint32_t chartIndex) const { return m_chartBasis[chartIndex]; }
- ConstArrayView<uint32_t> chartFaces(uint32_t chartIndex) const {
+ ConstArrayView<uint32_t> chartFaces(uint32_t chartIndex) const
+ {
const Chart &chart = m_charts[chartIndex];
return ConstArrayView<uint32_t>(&m_chartFaces[chart.firstFace], chart.faceCount);
}
- void compute() {
+ void compute()
+ {
m_charts.clear();
m_chartFaces.clear();
const Mesh *mesh = m_data.mesh;
@@ -4805,7 +5089,8 @@ struct OriginalUvCharts {
}
// Compute basis for each chart.
m_chartBasis.resize(m_charts.size());
- for (uint32_t c = 0; c < m_charts.size(); c++) {
+ for (uint32_t c = 0; c < m_charts.size(); c++)
+ {
const Chart &chart = m_charts[c];
m_tempPoints.resize(chart.faceCount * 3);
for (uint32_t f = 0; f < chart.faceCount; f++) {
@@ -4818,11 +5103,13 @@ struct OriginalUvCharts {
}
private:
- struct Chart {
+ struct Chart
+ {
uint32_t firstFace, faceCount;
};
- void floodfillFaces(Chart &chart) {
+ void floodfillFaces(Chart &chart)
+ {
const bool isFaceAreaNegative = m_data.faceUvAreas[m_chartFaces[chart.firstFace]] < 0.0f;
for (;;) {
bool newFaceAdded = false;
@@ -4868,13 +5155,14 @@ static uint32_t s_planarRegionsCurrentRegion;
static uint32_t s_planarRegionsCurrentVertex;
#endif
-struct PlanarCharts {
- PlanarCharts(AtlasData &data) :
- m_data(data), m_nextRegionFace(MemTag::SegmentAtlasPlanarRegions), m_faceToRegionId(MemTag::SegmentAtlasPlanarRegions) {}
+struct PlanarCharts
+{
+ PlanarCharts(AtlasData &data) : m_data(data), m_nextRegionFace(MemTag::SegmentAtlasPlanarRegions), m_faceToRegionId(MemTag::SegmentAtlasPlanarRegions) {}
const Basis &chartBasis(uint32_t chartIndex) const { return m_chartBasis[chartIndex]; }
uint32_t chartCount() const { return m_charts.size(); }
- ConstArrayView<uint32_t> chartFaces(uint32_t chartIndex) const {
+ ConstArrayView<uint32_t> chartFaces(uint32_t chartIndex) const
+ {
const Chart &chart = m_charts[chartIndex];
return ConstArrayView<uint32_t>(&m_chartFaces[chart.firstFace], chart.faceCount);
}
@@ -4883,7 +5171,8 @@ struct PlanarCharts {
uint32_t nextRegionFace(uint32_t face) const { return m_nextRegionFace[face]; }
float regionArea(uint32_t region) const { return m_regionAreas[region]; }
- void compute() {
+ void compute()
+ {
const uint32_t faceCount = m_data.mesh->faceCount();
// Precompute regions of coplanar incident faces.
m_regionFirstFace.clear();
@@ -4983,7 +5272,8 @@ struct PlanarCharts {
if (!createChart)
break;
face = m_nextRegionFace[face];
- } while (face != firstRegionFace);
+ }
+ while (face != firstRegionFace);
// Create a chart.
if (createChart) {
Chart chart;
@@ -4995,13 +5285,15 @@ struct PlanarCharts {
m_chartFaces.push_back(face);
chart.faceCount++;
face = m_nextRegionFace[face];
- } while (face != firstRegionFace);
+ }
+ while (face != firstRegionFace);
m_charts.push_back(chart);
}
}
// Compute basis for each chart using the first face normal (all faces have the same normal).
m_chartBasis.resize(m_charts.size());
- for (uint32_t c = 0; c < m_charts.size(); c++) {
+ for (uint32_t c = 0; c < m_charts.size(); c++)
+ {
const uint32_t face = m_chartFaces[m_charts[c].firstFace];
Basis &basis = m_chartBasis[c];
basis.normal = m_data.faceNormals[face];
@@ -5011,7 +5303,8 @@ struct PlanarCharts {
}
private:
- struct Chart {
+ struct Chart
+ {
uint32_t firstFace, faceCount;
};
@@ -5025,11 +5318,12 @@ private:
Array<Basis> m_chartBasis;
};
-struct ClusteredCharts {
- ClusteredCharts(AtlasData &data, const PlanarCharts &planarCharts) :
- m_data(data), m_planarCharts(planarCharts), m_texcoords(MemTag::SegmentAtlasMeshData), m_bestTriangles(10), m_placingSeeds(false) {}
+struct ClusteredCharts
+{
+ ClusteredCharts(AtlasData &data, const PlanarCharts &planarCharts) : m_data(data), m_planarCharts(planarCharts), m_texcoords(MemTag::SegmentAtlasMeshData), m_bestTriangles(10), m_placingSeeds(false) {}
- ~ClusteredCharts() {
+ ~ClusteredCharts()
+ {
const uint32_t chartCount = m_charts.size();
for (uint32_t i = 0; i < chartCount; i++) {
m_charts[i]->~Chart();
@@ -5041,7 +5335,8 @@ struct ClusteredCharts {
ConstArrayView<uint32_t> chartFaces(uint32_t chartIndex) const { return m_charts[chartIndex]->faces; }
const Basis &chartBasis(uint32_t chartIndex) const { return m_charts[chartIndex]->basis; }
- void compute() {
+ void compute()
+ {
const uint32_t faceCount = m_data.mesh->faceCount();
m_facesLeft = 0;
for (uint32_t i = 0; i < faceCount; i++) {
@@ -5087,9 +5382,9 @@ struct ClusteredCharts {
}
private:
- struct Chart {
- Chart() :
- faces(MemTag::SegmentAtlasChartFaces) {}
+ struct Chart
+ {
+ Chart() : faces(MemTag::SegmentAtlasChartFaces) {}
int id = -1;
Basis basis; // Best fit normal.
@@ -5103,7 +5398,8 @@ private:
uint32_t seed;
};
- void placeSeeds(float threshold) {
+ void placeSeeds(float threshold)
+ {
XA_PROFILE_START(clusteredChartsPlaceSeeds)
m_placingSeeds = true;
// Instead of using a predefiened number of seeds:
@@ -5119,7 +5415,8 @@ private:
}
// Returns true if any of the charts can grow more.
- void growCharts(float threshold) {
+ void growCharts(float threshold)
+ {
XA_PROFILE_START(clusteredChartsGrow)
for (;;) {
if (m_facesLeft == 0)
@@ -5165,7 +5462,8 @@ private:
XA_PROFILE_END(clusteredChartsGrow)
}
- void resetCharts() {
+ void resetCharts()
+ {
XA_PROFILE_START(clusteredChartsReset)
const uint32_t faceCount = m_data.mesh->faceCount();
for (uint32_t i = 0; i < faceCount; i++) {
@@ -5196,7 +5494,8 @@ private:
XA_PROFILE_END(clusteredChartsReset)
}
- bool relocateSeeds() {
+ bool relocateSeeds()
+ {
XA_PROFILE_START(clusteredChartsRelocateSeeds)
bool anySeedChanged = false;
const uint32_t chartCount = m_charts.size();
@@ -5209,7 +5508,8 @@ private:
return anySeedChanged;
}
- void fillHoles(float threshold) {
+ void fillHoles(float threshold)
+ {
XA_PROFILE_START(clusteredChartsFillHoles)
while (m_facesLeft > 0)
createChart(threshold);
@@ -5217,7 +5517,8 @@ private:
}
#if XA_MERGE_CHARTS
- void mergeCharts() {
+ void mergeCharts()
+ {
XA_PROFILE_START(clusteredChartsMerge)
const uint32_t chartCount = m_charts.size();
// Merge charts progressively until there's none left to merge.
@@ -5286,7 +5587,7 @@ private:
if (m_sharedBoundaryLengthsNoSeams[cc] > 0.0f && equal(m_sharedBoundaryLengthsNoSeams[cc], chart2->boundaryLength, kEpsilon))
goto merge;
if (m_sharedBoundaryLengths[cc] > 0.2f * max(0.0f, chart->boundaryLength - externalBoundaryLength) ||
- m_sharedBoundaryLengths[cc] > 0.75f * chart2->boundaryLength)
+ m_sharedBoundaryLengths[cc] > 0.75f * chart2->boundaryLength)
goto merge;
continue;
merge:
@@ -5324,7 +5625,8 @@ private:
#endif
private:
- void createChart(float threshold) {
+ void createChart(float threshold)
+ {
Chart *chart = XA_NEW(MemTag::Default, Chart);
chart->id = (int)m_charts.size();
m_charts.push_back(chart);
@@ -5355,13 +5657,15 @@ private:
}
}
- bool isChartBoundaryEdge(const Chart *chart, uint32_t edge) const {
+ bool isChartBoundaryEdge(const Chart *chart, uint32_t edge) const
+ {
const uint32_t oppositeEdge = m_data.mesh->oppositeEdge(edge);
const uint32_t oppositeFace = meshEdgeFace(oppositeEdge);
return oppositeEdge == UINT32_MAX || m_faceCharts[oppositeFace] != chart->id;
}
- bool computeChartBasis(Chart *chart, Basis *basis) {
+ bool computeChartBasis(Chart *chart, Basis *basis)
+ {
const uint32_t faceCount = chart->faces.size();
m_tempPoints.resize(chart->faces.size() * 3);
for (uint32_t i = 0; i < faceCount; i++) {
@@ -5372,7 +5676,8 @@ private:
return Fit::computeBasis(m_tempPoints, basis);
}
- bool isFaceFlipped(uint32_t face) const {
+ bool isFaceFlipped(uint32_t face) const
+ {
const Vector2 &v1 = m_texcoords[face * 3 + 0];
const Vector2 &v2 = m_texcoords[face * 3 + 1];
const Vector2 &v3 = m_texcoords[face * 3 + 2];
@@ -5380,7 +5685,8 @@ private:
return parametricArea < 0.0f;
}
- void parameterizeChart(const Chart *chart) {
+ void parameterizeChart(const Chart *chart)
+ {
const uint32_t faceCount = chart->faces.size();
for (uint32_t i = 0; i < faceCount; i++) {
const uint32_t face = chart->faces[i];
@@ -5393,7 +5699,8 @@ private:
}
// m_faceCharts for the chart faces must be set to the chart ID. Needed to compute boundary edges.
- bool isChartParameterizationValid(const Chart *chart) {
+ bool isChartParameterizationValid(const Chart *chart)
+ {
const uint32_t faceCount = chart->faces.size();
// Check for flipped faces in the parameterization. OK if all are flipped.
uint32_t flippedFaceCount = 0;
@@ -5427,7 +5734,8 @@ private:
return true;
}
- bool addFaceToChart(Chart *chart, uint32_t face) {
+ bool addFaceToChart(Chart *chart, uint32_t face)
+ {
XA_DEBUG_ASSERT(!m_data.isFaceInChart.get(face));
const uint32_t oldFaceCount = chart->faces.size();
const bool firstFace = oldFaceCount == 0;
@@ -5505,7 +5813,8 @@ private:
}
// Returns true if the seed has changed.
- bool relocateSeed(Chart *chart) {
+ bool relocateSeed(Chart *chart)
+ {
// Find the first N triangles that fit the proxy best.
const uint32_t faceCount = chart->faces.size();
m_bestTriangles.clear();
@@ -5535,7 +5844,8 @@ private:
}
// Cost is combined metrics * weights.
- float computeCost(Chart *chart, uint32_t face) const {
+ float computeCost(Chart *chart, uint32_t face) const
+ {
// Estimate boundary length and area:
const float newChartArea = computeArea(chart, face);
const float newBoundaryLength = computeBoundaryLength(chart, face);
@@ -5571,20 +5881,23 @@ private:
// Returns a value in [0-1].
// 0 if face normal is coplanar to the chart's best fit normal.
// 1 if face normal is perpendicular.
- float computeNormalDeviationMetric(Chart *chart, uint32_t face) const {
+ float computeNormalDeviationMetric(Chart *chart, uint32_t face) const
+ {
// All faces in coplanar regions have the same normal, can use any face.
const Vector3 faceNormal = m_data.faceNormals[face];
// Use plane fitting metric for now:
return min(1.0f - dot(faceNormal, chart->basis.normal), 1.0f); // @@ normal deviations should be weighted by face area
}
- float computeRoundnessMetric(Chart *chart, float newBoundaryLength, float newChartArea) const {
+ float computeRoundnessMetric(Chart *chart, float newBoundaryLength, float newChartArea) const
+ {
const float oldRoundness = square(chart->boundaryLength) / chart->area;
const float newRoundness = square(newBoundaryLength) / newChartArea;
return 1.0f - oldRoundness / newRoundness;
}
- float computeStraightnessMetric(Chart *chart, uint32_t firstFace) const {
+ float computeStraightnessMetric(Chart *chart, uint32_t firstFace) const
+ {
float l_out = 0.0f; // Length of firstFace planar region boundary that doesn't border the chart.
float l_in = 0.0f; // Length that does border the chart.
const uint32_t planarRegionId = m_planarCharts.regionIdFromFace(firstFace);
@@ -5613,7 +5926,8 @@ private:
#endif
}
- bool isNormalSeam(uint32_t edge) const {
+ bool isNormalSeam(uint32_t edge) const
+ {
const uint32_t oppositeEdge = m_data.mesh->oppositeEdge(edge);
if (oppositeEdge == UINT32_MAX)
return false; // boundary edge
@@ -5633,7 +5947,8 @@ private:
return !equal(m_data.faceNormals[f0], m_data.faceNormals[f1], kNormalEpsilon);
}
- float computeNormalSeamMetric(Chart *chart, uint32_t firstFace) const {
+ float computeNormalSeamMetric(Chart *chart, uint32_t firstFace) const
+ {
float seamFactor = 0.0f, totalLength = 0.0f;
uint32_t face = firstFace;
for (;;) {
@@ -5673,7 +5988,8 @@ private:
return seamFactor / totalLength;
}
- float computeTextureSeamMetric(Chart *chart, uint32_t firstFace) const {
+ float computeTextureSeamMetric(Chart *chart, uint32_t firstFace) const
+ {
float seamLength = 0.0f, totalLength = 0.0f;
uint32_t face = firstFace;
for (;;) {
@@ -5699,7 +6015,8 @@ private:
return seamLength / totalLength;
}
- float computeArea(Chart *chart, uint32_t firstFace) const {
+ float computeArea(Chart *chart, uint32_t firstFace) const
+ {
float area = chart->area;
uint32_t face = firstFace;
for (;;) {
@@ -5711,7 +6028,8 @@ private:
return area;
}
- float computeBoundaryLength(Chart *chart, uint32_t firstFace) const {
+ float computeBoundaryLength(Chart *chart, uint32_t firstFace) const
+ {
float boundaryLength = chart->boundaryLength;
// Add new edges, subtract edges shared with the chart.
const uint32_t planarRegionId = m_planarCharts.regionIdFromFace(firstFace);
@@ -5732,10 +6050,11 @@ private:
if (face == firstFace)
break;
}
- return max(0.0f, boundaryLength); // @@ Hack!
+ return max(0.0f, boundaryLength); // @@ Hack!
}
- bool mergeChart(Chart *owner, Chart *chart, float sharedBoundaryLength) {
+ bool mergeChart(Chart *owner, Chart *chart, float sharedBoundaryLength)
+ {
const uint32_t oldOwnerFaceCount = owner->faces.size();
const uint32_t chartFaceCount = chart->faces.size();
owner->faces.push_back(chart->faces);
@@ -5793,8 +6112,10 @@ private:
bool m_placingSeeds;
};
-struct ChartGeneratorType {
- enum Enum {
+struct ChartGeneratorType
+{
+ enum Enum
+ {
OriginalUv,
Planar,
Clustered,
@@ -5802,15 +6123,17 @@ struct ChartGeneratorType {
};
};
-struct Atlas {
- Atlas() :
- m_originalUvCharts(m_data), m_planarCharts(m_data), m_clusteredCharts(m_data, m_planarCharts) {}
+struct Atlas
+{
+ Atlas() : m_originalUvCharts(m_data), m_planarCharts(m_data), m_clusteredCharts(m_data, m_planarCharts) {}
- uint32_t chartCount() const {
+ uint32_t chartCount() const
+ {
return m_originalUvCharts.chartCount() + m_planarCharts.chartCount() + m_clusteredCharts.chartCount();
}
- ConstArrayView<uint32_t> chartFaces(uint32_t chartIndex) const {
+ ConstArrayView<uint32_t> chartFaces(uint32_t chartIndex) const
+ {
if (chartIndex < m_originalUvCharts.chartCount())
return m_originalUvCharts.chartFaces(chartIndex);
chartIndex -= m_originalUvCharts.chartCount();
@@ -5820,7 +6143,8 @@ struct Atlas {
return m_clusteredCharts.chartFaces(chartIndex);
}
- const Basis &chartBasis(uint32_t chartIndex) const {
+ const Basis &chartBasis(uint32_t chartIndex) const
+ {
if (chartIndex < m_originalUvCharts.chartCount())
return m_originalUvCharts.chartBasis(chartIndex);
chartIndex -= m_originalUvCharts.chartCount();
@@ -5830,7 +6154,8 @@ struct Atlas {
return m_clusteredCharts.chartBasis(chartIndex);
}
- ChartGeneratorType::Enum chartGeneratorType(uint32_t chartIndex) const {
+ ChartGeneratorType::Enum chartGeneratorType(uint32_t chartIndex) const
+ {
if (chartIndex < m_originalUvCharts.chartCount())
return ChartGeneratorType::OriginalUv;
chartIndex -= m_originalUvCharts.chartCount();
@@ -5839,7 +6164,8 @@ struct Atlas {
return ChartGeneratorType::Clustered;
}
- void reset(const Mesh *mesh, const ChartOptions &options) {
+ void reset(const Mesh *mesh, const ChartOptions &options)
+ {
XA_PROFILE_START(buildAtlasInit)
m_data.options = options;
m_data.mesh = mesh;
@@ -5847,7 +6173,8 @@ struct Atlas {
XA_PROFILE_END(buildAtlasInit)
}
- void compute() {
+ void compute()
+ {
if (m_data.options.useInputMeshUvs) {
XA_PROFILE_START(originalUvCharts)
m_originalUvCharts.compute();
@@ -5868,17 +6195,19 @@ private:
ClusteredCharts m_clusteredCharts;
};
-struct ComputeUvMeshChartsTaskArgs {
+struct ComputeUvMeshChartsTaskArgs
+{
UvMesh *mesh;
Progress *progress;
};
// Charts are found by floodfilling faces without crossing UV seams.
-struct ComputeUvMeshChartsTask {
- ComputeUvMeshChartsTask(ComputeUvMeshChartsTaskArgs *args) :
- m_mesh(args->mesh), m_progress(args->progress), m_uvToEdgeMap(MemTag::Default, m_mesh->indices.size()), m_faceAssigned(m_mesh->indices.size() / 3) {}
+struct ComputeUvMeshChartsTask
+{
+ ComputeUvMeshChartsTask(ComputeUvMeshChartsTaskArgs *args) : m_mesh(args->mesh), m_progress(args->progress), m_uvToEdgeMap(MemTag::Default, m_mesh->indices.size()), m_faceAssigned(m_mesh->indices.size() / 3) {}
- void run() {
+ void run()
+ {
const uint32_t vertexCount = m_mesh->texcoords.size();
const uint32_t indexCount = m_mesh->indices.size();
const uint32_t faceCount = indexCount / 3;
@@ -5932,7 +6261,8 @@ struct ComputeUvMeshChartsTask {
private:
// The chart at chartIndex doesn't have to exist yet.
- bool canAddFaceToChart(uint32_t chartIndex, uint32_t face) const {
+ bool canAddFaceToChart(uint32_t chartIndex, uint32_t face) const
+ {
if (m_faceAssigned.get(face))
return false; // Already assigned to a chart.
if (m_mesh->faceIgnore.get(face))
@@ -5949,7 +6279,8 @@ private:
return true;
}
- void addFaceToChart(uint32_t chartIndex, uint32_t face) {
+ void addFaceToChart(uint32_t chartIndex, uint32_t face)
+ {
UvMeshChart *chart = m_mesh->charts[chartIndex];
m_faceAssigned.set(face);
chart->faces.push_back(face);
@@ -5960,20 +6291,22 @@ private:
}
}
- UvMesh *const m_mesh;
- Progress *const m_progress;
+ UvMesh * const m_mesh;
+ Progress * const m_progress;
HashMap<Vector2> m_uvToEdgeMap; // Face is edge / 3.
BitArray m_faceAssigned;
};
-static void runComputeUvMeshChartsTask(void * /*groupUserData*/, void *taskUserData) {
+static void runComputeUvMeshChartsTask(void * /*groupUserData*/, void *taskUserData)
+{
XA_PROFILE_START(computeChartsThread)
ComputeUvMeshChartsTask task((ComputeUvMeshChartsTaskArgs *)taskUserData);
task.run();
XA_PROFILE_END(computeChartsThread)
}
-static bool computeUvMeshCharts(TaskScheduler *taskScheduler, ArrayView<UvMesh *> meshes, ProgressFunc progressFunc, void *progressUserData) {
+static bool computeUvMeshCharts(TaskScheduler *taskScheduler, ArrayView<UvMesh *> meshes, ProgressFunc progressFunc, void *progressUserData)
+{
uint32_t totalFaceCount = 0;
for (uint32_t i = 0; i < meshes.length; i++)
totalFaceCount += meshes[i]->indices.size() / 3;
@@ -5981,7 +6314,8 @@ static bool computeUvMeshCharts(TaskScheduler *taskScheduler, ArrayView<UvMesh *
TaskGroupHandle taskGroup = taskScheduler->createTaskGroup(nullptr, meshes.length);
Array<ComputeUvMeshChartsTaskArgs> taskArgs;
taskArgs.resize(meshes.length);
- for (uint32_t i = 0; i < meshes.length; i++) {
+ for (uint32_t i = 0; i < meshes.length; i++)
+ {
ComputeUvMeshChartsTaskArgs &args = taskArgs[i];
args.mesh = meshes[i];
args.progress = &progress;
@@ -5999,7 +6333,8 @@ static bool computeUvMeshCharts(TaskScheduler *taskScheduler, ArrayView<UvMesh *
namespace param {
// Fast sweep in 3 directions
-static bool findApproximateDiameterVertices(Mesh *mesh, uint32_t *a, uint32_t *b) {
+static bool findApproximateDiameterVertices(Mesh *mesh, uint32_t *a, uint32_t *b)
+{
XA_DEBUG_ASSERT(a != nullptr);
XA_DEBUG_ASSERT(b != nullptr);
const uint32_t vertexCount = mesh->vertexCount();
@@ -6056,7 +6391,8 @@ static bool findApproximateDiameterVertices(Mesh *mesh, uint32_t *a, uint32_t *b
// From OpenNL LSCM example.
// Computes the coordinates of the vertices of a triangle in a local 2D orthonormal basis of the triangle's plane.
-static void projectTriangle(Vector3 p0, Vector3 p1, Vector3 p2, Vector2 *z0, Vector2 *z1, Vector2 *z2) {
+static void projectTriangle(Vector3 p0, Vector3 p1, Vector3 p2, Vector2 *z0, Vector2 *z1, Vector2 *z2)
+{
Vector3 X = normalize(p1 - p0);
Vector3 Z = normalize(cross(X, p2 - p0));
Vector3 Y = cross(Z, X);
@@ -6068,24 +6404,28 @@ static void projectTriangle(Vector3 p0, Vector3 p1, Vector3 p2, Vector2 *z0, Vec
// Conformal relations from Brecht Van Lommel (based on ABF):
-static float vec_angle_cos(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3) {
+static float vec_angle_cos(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3)
+{
Vector3 d1 = v1 - v2;
Vector3 d2 = v3 - v2;
return clamp(dot(d1, d2) / (length(d1) * length(d2)), -1.0f, 1.0f);
}
-static float vec_angle(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3) {
+static float vec_angle(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3)
+{
float dot = vec_angle_cos(v1, v2, v3);
return acosf(dot);
}
-static void triangle_angles(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, float *a1, float *a2, float *a3) {
+static void triangle_angles(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, float *a1, float *a2, float *a3)
+{
*a1 = vec_angle(v3, v1, v2);
*a2 = vec_angle(v1, v2, v3);
*a3 = kPi - *a2 - *a1;
}
-static bool setup_abf_relations(opennl::NLContext *context, int id0, int id1, int id2, const Vector3 &p0, const Vector3 &p1, const Vector3 &p2) {
+static bool setup_abf_relations(opennl::NLContext *context, int id0, int id1, int id2, const Vector3 &p0, const Vector3 &p1, const Vector3 &p2)
+{
// @@ IC: Wouldn't it be more accurate to return cos and compute 1-cos^2?
// It does indeed seem to be a little bit more robust.
// @@ Need to revisit this more carefully!
@@ -6142,7 +6482,8 @@ static bool setup_abf_relations(opennl::NLContext *context, int id0, int id1, in
return true;
}
-static bool computeLeastSquaresConformalMap(Mesh *mesh) {
+static bool computeLeastSquaresConformalMap(Mesh *mesh)
+{
uint32_t lockedVertex0, lockedVertex1;
if (!findApproximateDiameterVertices(mesh, &lockedVertex0, &lockedVertex1)) {
// Mesh has no boundaries.
@@ -6189,16 +6530,16 @@ static bool computeLeastSquaresConformalMap(Mesh *mesh) {
// Note : b = 0
// Real part
opennl::nlBegin(context, NL_ROW);
- opennl::nlCoefficient(context, u0_id, -a + c);
- opennl::nlCoefficient(context, v0_id, b - d);
- opennl::nlCoefficient(context, u1_id, -c);
- opennl::nlCoefficient(context, v1_id, d);
+ opennl::nlCoefficient(context, u0_id, -a+c) ;
+ opennl::nlCoefficient(context, v0_id, b-d) ;
+ opennl::nlCoefficient(context, u1_id, -c) ;
+ opennl::nlCoefficient(context, v1_id, d) ;
opennl::nlCoefficient(context, u2_id, a);
opennl::nlEnd(context, NL_ROW);
// Imaginary part
opennl::nlBegin(context, NL_ROW);
- opennl::nlCoefficient(context, u0_id, -b + d);
- opennl::nlCoefficient(context, v0_id, -a + c);
+ opennl::nlCoefficient(context, u0_id, -b+d);
+ opennl::nlCoefficient(context, v0_id, -a+c);
opennl::nlCoefficient(context, u1_id, -d);
opennl::nlCoefficient(context, v1_id, -c);
opennl::nlCoefficient(context, v2_id, a);
@@ -6222,8 +6563,10 @@ static bool computeLeastSquaresConformalMap(Mesh *mesh) {
return true;
}
-struct PiecewiseParam {
- void reset(const Mesh *mesh) {
+struct PiecewiseParam
+{
+ void reset(const Mesh *mesh)
+ {
m_mesh = mesh;
const uint32_t faceCount = m_mesh->faceCount();
const uint32_t vertexCount = m_mesh->vertexCount();
@@ -6241,7 +6584,8 @@ struct PiecewiseParam {
ConstArrayView<uint32_t> chartFaces() const { return m_patch; }
ConstArrayView<Vector2> texcoords() const { return m_texcoords; }
- bool computeChart() {
+ bool computeChart()
+ {
// Clear per-patch state.
m_patch.clear();
m_candidates.clear();
@@ -6370,7 +6714,8 @@ struct PiecewiseParam {
}
private:
- struct Candidate {
+ struct Candidate
+ {
uint32_t face, vertex;
Candidate *prev, *next; // The previous/next candidate with the same vertex.
Vector2 position;
@@ -6380,14 +6725,10 @@ private:
float patchVertexOrient;
};
- struct CandidateIterator {
- CandidateIterator(Candidate *head) :
- m_current(head) { XA_DEBUG_ASSERT(!head->prev); }
- void advance() {
- if (m_current != nullptr) {
- m_current = m_current->next;
- }
- }
+ struct CandidateIterator
+ {
+ CandidateIterator(Candidate *head) : m_current(head) { XA_DEBUG_ASSERT(!head->prev); }
+ void advance() { if (m_current != nullptr) { m_current = m_current->next; } }
bool isDone() const { return !m_current; }
Candidate *current() { return m_current; }
@@ -6406,7 +6747,8 @@ private:
UniformGrid2 m_boundaryGrid;
Array<uint32_t> m_newBoundaryEdges, m_ignoreBoundaryEdges; // Temp arrays used when testing for boundary intersection.
- void addFaceToPatch(uint32_t face) {
+ void addFaceToPatch(uint32_t face)
+ {
XA_DEBUG_ASSERT(!m_faceInPatch.get(face));
XA_DEBUG_ASSERT(!m_faceInAnyPatch.get(face));
m_patch.push_back(face);
@@ -6446,7 +6788,8 @@ private:
}
}
- void addCandidateFace(uint32_t patchEdge, float patchVertexOrient, uint32_t face, uint32_t edge, uint32_t freeVertex) {
+ void addCandidateFace(uint32_t patchEdge, float patchVertexOrient, uint32_t face, uint32_t edge, uint32_t freeVertex)
+ {
XA_DEBUG_ASSERT(!m_faceToCandidate[face]);
Vector2 texcoords[3];
orthoProjectFace(face, texcoords);
@@ -6549,7 +6892,8 @@ private:
it.current()->maxCost = maxCost;
}
- Candidate *linkedCandidateHead(Candidate *candidate) {
+ Candidate *linkedCandidateHead(Candidate *candidate)
+ {
Candidate *current = candidate;
for (;;) {
if (!current->prev)
@@ -6559,7 +6903,8 @@ private:
return current;
}
- void removeLinkedCandidates(Candidate *head) {
+ void removeLinkedCandidates(Candidate *head)
+ {
XA_DEBUG_ASSERT(!head->prev);
Candidate *current = head;
while (current) {
@@ -6576,7 +6921,8 @@ private:
}
}
- void orthoProjectFace(uint32_t face, Vector2 *texcoords) const {
+ void orthoProjectFace(uint32_t face, Vector2 *texcoords) const
+ {
const Vector3 normal = -m_mesh->computeFaceNormal(face);
const Vector3 tangent = normalize(m_mesh->position(m_mesh->vertexAt(face * 3 + 1)) - m_mesh->position(m_mesh->vertexAt(face * 3 + 0)));
const Vector3 bitangent = cross(normal, tangent);
@@ -6586,14 +6932,16 @@ private:
}
}
- float parametricArea(const Vector2 *texcoords) const {
+ float parametricArea(const Vector2 *texcoords) const
+ {
const Vector2 &v1 = texcoords[0];
const Vector2 &v2 = texcoords[1];
const Vector2 &v3 = texcoords[2];
return ((v2.x - v1.x) * (v3.y - v1.y) - (v3.x - v1.x) * (v2.y - v1.y)) * 0.5f;
}
- float computeStretch(Vector3 p1, Vector3 p2, Vector3 p3, Vector2 t1, Vector2 t2, Vector2 t3) const {
+ float computeStretch(Vector3 p1, Vector3 p2, Vector3 p3, Vector2 t1, Vector2 t2, Vector2 t3) const
+ {
float parametricArea = ((t2.y - t1.y) * (t3.x - t1.x) - (t3.y - t1.y) * (t2.x - t1.x)) * 0.5f;
if (isZero(parametricArea, kAreaEpsilon))
return FLT_MAX;
@@ -6607,13 +6955,15 @@ private:
}
// Return value is positive if the point is one side of the edge, negative if on the other side.
- float orientToEdge(Vector2 edgeVertex0, Vector2 edgeVertex1, Vector2 point) const {
+ float orientToEdge(Vector2 edgeVertex0, Vector2 edgeVertex1, Vector2 point) const
+ {
return (edgeVertex0.x - point.x) * (edgeVertex1.y - point.y) - (edgeVertex0.y - point.y) * (edgeVertex1.x - point.x);
}
};
// Estimate quality of existing parameterization.
-struct Quality {
+struct Quality
+{
// computeBoundaryIntersection
bool boundaryIntersection = false;
@@ -6630,7 +6980,8 @@ struct Quality {
float conformalMetric = 0.0f;
float authalicMetric = 0.0f;
- void computeBoundaryIntersection(const Mesh *mesh, UniformGrid2 &boundaryGrid) {
+ void computeBoundaryIntersection(const Mesh *mesh, UniformGrid2 &boundaryGrid)
+ {
const Array<uint32_t> &boundaryEdges = mesh->boundaryEdges();
const uint32_t boundaryEdgeCount = boundaryEdges.size();
boundaryGrid.reset(mesh->texcoords(), mesh->indices(), boundaryEdgeCount);
@@ -6646,7 +6997,8 @@ struct Quality {
#endif
}
- void computeFlippedFaces(const Mesh *mesh, Array<uint32_t> *flippedFaces) {
+ void computeFlippedFaces(const Mesh *mesh, Array<uint32_t> *flippedFaces)
+ {
totalTriangleCount = flippedTriangleCount = zeroAreaTriangleCount = 0;
if (flippedFaces)
flippedFaces->clear();
@@ -6682,7 +7034,8 @@ struct Quality {
flippedFaces->clear();
flippedTriangleCount = 0;
}
- if (flippedTriangleCount > totalTriangleCount / 2) {
+ if (flippedTriangleCount > totalTriangleCount / 2)
+ {
// If more than half the triangles are flipped, reverse the flipped / not flipped classification.
flippedTriangleCount = totalTriangleCount - flippedTriangleCount;
if (flippedFaces) {
@@ -6704,7 +7057,8 @@ struct Quality {
}
}
- void computeMetrics(const Mesh *mesh) {
+ void computeMetrics(const Mesh *mesh)
+ {
totalGeometricArea = totalParametricArea = 0.0f;
stretchMetric = maxStretchMetric = conformalMetric = authalicMetric = 0.0f;
const uint32_t faceCount = mesh->faceCount();
@@ -6736,7 +7090,7 @@ struct Quality {
const float a = dot(Ss, Ss); // E
const float b = dot(Ss, St); // F
const float c = dot(St, St); // G
- // Compute eigen-values of the first fundamental form:
+ // Compute eigen-values of the first fundamental form:
const float sigma1 = sqrtf(0.5f * max(0.0f, a + c - sqrtf(square(a - c) + 4 * square(b)))); // gamma uppercase, min eigenvalue.
const float sigma2 = sqrtf(0.5f * max(0.0f, a + c + sqrtf(square(a - c) + 4 * square(b)))); // gamma lowercase, max eigenvalue.
XA_ASSERT(sigma2 > sigma1 || equal(sigma1, sigma2, kEpsilon));
@@ -6767,22 +7121,24 @@ struct Quality {
if (totalGeometricArea > 0.0f) {
const float normFactor = sqrtf(totalParametricArea / totalGeometricArea);
stretchMetric = sqrtf(stretchMetric / totalGeometricArea) * normFactor;
- maxStretchMetric *= normFactor;
+ maxStretchMetric *= normFactor;
conformalMetric = sqrtf(conformalMetric / totalGeometricArea);
authalicMetric = sqrtf(authalicMetric / totalGeometricArea);
}
}
};
-struct ChartCtorBuffers {
+struct ChartCtorBuffers
+{
Array<uint32_t> chartMeshIndices;
Array<uint32_t> unifiedMeshIndices;
};
-class Chart {
+class Chart
+{
public:
- Chart(const Basis &basis, segment::ChartGeneratorType::Enum generatorType, ConstArrayView<uint32_t> faces, const Mesh *sourceMesh, uint32_t chartGroupId, uint32_t chartId) :
- m_basis(basis), m_unifiedMesh(nullptr), m_type(ChartType::LSCM), m_generatorType(generatorType), m_tjunctionCount(0), m_originalVertexCount(0), m_isInvalid(false) {
+ Chart(const Basis &basis, segment::ChartGeneratorType::Enum generatorType, ConstArrayView<uint32_t> faces, const Mesh *sourceMesh, uint32_t chartGroupId, uint32_t chartId) : m_basis(basis), m_unifiedMesh(nullptr), m_type(ChartType::LSCM), m_generatorType(generatorType), m_tjunctionCount(0), m_originalVertexCount(0), m_isInvalid(false)
+ {
XA_UNUSED(chartGroupId);
XA_UNUSED(chartId);
m_faceToSourceFaceMap.copyFrom(faces.data, faces.length);
@@ -6813,8 +7169,7 @@ public:
m_chartVertexToUnifiedVertexMap.push_back(unifiedVertex);
m_originalVertexCount++;
}
- m_originalIndices[f * 3 + i] = sourceVertexToChartVertexMap.get(sourceVertex);
- ;
+ m_originalIndices[f * 3 + i] = sourceVertexToChartVertexMap.get(sourceVertex);;
XA_DEBUG_ASSERT(m_originalIndices[f * 3 + i] != UINT32_MAX);
unifiedIndices[i] = sourceVertexToUnifiedVertexMap.get(sourceUnifiedVertex);
XA_DEBUG_ASSERT(unifiedIndices[i] != UINT32_MAX);
@@ -6838,8 +7193,8 @@ public:
#endif
}
- Chart(ChartCtorBuffers &buffers, const Chart *parent, const Mesh *parentMesh, ConstArrayView<uint32_t> faces, ConstArrayView<Vector2> texcoords, const Mesh *sourceMesh) :
- m_unifiedMesh(nullptr), m_type(ChartType::Piecewise), m_generatorType(segment::ChartGeneratorType::Piecewise), m_tjunctionCount(0), m_originalVertexCount(0), m_isInvalid(false) {
+ Chart(ChartCtorBuffers &buffers, const Chart *parent, const Mesh *parentMesh, ConstArrayView<uint32_t> faces, ConstArrayView<Vector2> texcoords, const Mesh *sourceMesh) : m_unifiedMesh(nullptr), m_type(ChartType::Piecewise), m_generatorType(segment::ChartGeneratorType::Piecewise), m_tjunctionCount(0), m_originalVertexCount(0), m_isInvalid(false)
+ {
const uint32_t faceCount = faces.length;
m_faceToSourceFaceMap.resize(faceCount);
for (uint32_t i = 0; i < faceCount; i++)
@@ -6886,7 +7241,8 @@ public:
backupTexcoords();
}
- ~Chart() {
+ ~Chart()
+ {
if (m_unifiedMesh) {
m_unifiedMesh->~Mesh();
XA_FREE(m_unifiedMesh);
@@ -6914,7 +7270,8 @@ public:
ConstArrayView<uint32_t> originalVertices() const { return m_originalIndices; }
- void parameterize(const ChartOptions &options, UniformGrid2 &boundaryGrid) {
+ void parameterize(const ChartOptions &options, UniformGrid2 &boundaryGrid)
+ {
const uint32_t unifiedVertexCount = m_unifiedMesh->vertexCount();
if (m_generatorType == segment::ChartGeneratorType::OriginalUv) {
} else {
@@ -6938,7 +7295,8 @@ public:
XA_PROFILE_START(parameterizeChartsLSCM)
if (options.paramFunc) {
options.paramFunc(&m_unifiedMesh->position(0).x, &m_unifiedMesh->texcoord(0).x, m_unifiedMesh->vertexCount(), m_unifiedMesh->indices().data, m_unifiedMesh->indexCount());
- } else
+ }
+ else
computeLeastSquaresConformalMap(m_unifiedMesh);
XA_PROFILE_END(parameterizeChartsLSCM)
XA_PROFILE_START(parameterizeChartsEvaluateQuality)
@@ -6980,7 +7338,8 @@ public:
backupTexcoords();
}
- Vector2 computeParametricBounds() const {
+ Vector2 computeParametricBounds() const
+ {
Vector2 minCorner(FLT_MAX, FLT_MAX);
Vector2 maxCorner(-FLT_MAX, -FLT_MAX);
const uint32_t vertexCount = m_unifiedMesh->vertexCount();
@@ -6992,7 +7351,8 @@ public:
}
#if XA_CHECK_PIECEWISE_CHART_QUALITY
- void evaluateQuality(UniformGrid2 &boundaryGrid) {
+ void evaluateQuality(UniformGrid2 &boundaryGrid)
+ {
m_quality.computeBoundaryIntersection(m_unifiedMesh, boundaryGrid);
#if XA_DEBUG_EXPORT_OBJ_INVALID_PARAMETERIZATION
m_quality.computeFlippedFaces(m_unifiedMesh, &m_paramFlippedFaces);
@@ -7004,12 +7364,14 @@ public:
}
#endif
- void restoreTexcoords() {
+ void restoreTexcoords()
+ {
memcpy(m_unifiedMesh->texcoords().data, m_backupTexcoords.data(), m_unifiedMesh->vertexCount() * sizeof(Vector2));
}
private:
- void backupTexcoords() {
+ void backupTexcoords()
+ {
m_backupTexcoords.resize(m_unifiedMesh->vertexCount());
memcpy(m_backupTexcoords.data(), m_unifiedMesh->texcoords().data, m_unifiedMesh->vertexCount() * sizeof(Vector2));
}
@@ -7040,7 +7402,8 @@ private:
bool m_isInvalid;
};
-struct CreateAndParameterizeChartTaskGroupArgs {
+struct CreateAndParameterizeChartTaskGroupArgs
+{
Progress *progress;
ThreadLocal<UniformGrid2> *boundaryGrid;
ThreadLocal<ChartCtorBuffers> *chartBuffers;
@@ -7048,7 +7411,8 @@ struct CreateAndParameterizeChartTaskGroupArgs {
ThreadLocal<PiecewiseParam> *pp;
};
-struct CreateAndParameterizeChartTaskArgs {
+struct CreateAndParameterizeChartTaskArgs
+{
const Basis *basis;
Chart *chart; // output
Array<Chart *> charts; // output (if more than one chart)
@@ -7059,7 +7423,8 @@ struct CreateAndParameterizeChartTaskArgs {
uint32_t chartId;
};
-static void runCreateAndParameterizeChartTask(void *groupUserData, void *taskUserData) {
+static void runCreateAndParameterizeChartTask(void *groupUserData, void *taskUserData)
+{
XA_PROFILE_START(createChartMeshAndParameterizeThread)
auto groupArgs = (CreateAndParameterizeChartTaskGroupArgs *)groupUserData;
auto args = (CreateAndParameterizeChartTaskArgs *)taskUserData;
@@ -7130,13 +7495,15 @@ static void runCreateAndParameterizeChartTask(void *groupUserData, void *taskUse
}
// Set of charts corresponding to mesh faces in the same face group.
-class ChartGroup {
+class ChartGroup
+{
public:
- ChartGroup(uint32_t id, const Mesh *sourceMesh, const MeshFaceGroups *sourceMeshFaceGroups, MeshFaceGroups::Handle faceGroup) :
- m_id(id), m_sourceMesh(sourceMesh), m_sourceMeshFaceGroups(sourceMeshFaceGroups), m_faceGroup(faceGroup) {
+ ChartGroup(uint32_t id, const Mesh *sourceMesh, const MeshFaceGroups *sourceMeshFaceGroups, MeshFaceGroups::Handle faceGroup) : m_id(id), m_sourceMesh(sourceMesh), m_sourceMeshFaceGroups(sourceMeshFaceGroups), m_faceGroup(faceGroup)
+ {
}
- ~ChartGroup() {
+ ~ChartGroup()
+ {
for (uint32_t i = 0; i < m_charts.size(); i++) {
m_charts[i]->~Chart();
XA_FREE(m_charts[i]);
@@ -7147,7 +7514,8 @@ public:
Chart *chartAt(uint32_t i) const { return m_charts[i]; }
uint32_t faceCount() const { return m_sourceMeshFaceGroups->faceCount(m_faceGroup); }
- void computeCharts(TaskScheduler *taskScheduler, const ChartOptions &options, Progress *progress, segment::Atlas &atlas, ThreadLocal<UniformGrid2> *boundaryGrid, ThreadLocal<ChartCtorBuffers> *chartBuffers, ThreadLocal<PiecewiseParam> *piecewiseParam) {
+ void computeCharts(TaskScheduler *taskScheduler, const ChartOptions &options, Progress *progress, segment::Atlas &atlas, ThreadLocal<UniformGrid2> *boundaryGrid, ThreadLocal<ChartCtorBuffers> *chartBuffers, ThreadLocal<PiecewiseParam> *piecewiseParam)
+ {
// This function may be called multiple times, so destroy existing charts.
for (uint32_t i = 0; i < m_charts.size(); i++) {
m_charts[i]->~Chart();
@@ -7291,7 +7659,8 @@ public:
}
private:
- Mesh *createMesh() {
+ Mesh *createMesh()
+ {
XA_DEBUG_ASSERT(m_faceGroup != MeshFaceGroups::kInvalid);
// Create new mesh from the source mesh, using faces that belong to this group.
m_faceToSourceFaceMap.reserve(m_sourceMeshFaceGroups->faceCount(m_faceGroup));
@@ -7345,14 +7714,15 @@ private:
}
const uint32_t m_id;
- const Mesh *const m_sourceMesh;
- const MeshFaceGroups *const m_sourceMeshFaceGroups;
+ const Mesh * const m_sourceMesh;
+ const MeshFaceGroups * const m_sourceMeshFaceGroups;
const MeshFaceGroups::Handle m_faceGroup;
Array<uint32_t> m_faceToSourceFaceMap; // List of faces of the source mesh that belong to this chart group.
Array<Chart *> m_charts;
};
-struct ChartGroupComputeChartsTaskGroupArgs {
+struct ChartGroupComputeChartsTaskGroupArgs
+{
ThreadLocal<segment::Atlas> *atlas;
const ChartOptions *options;
Progress *progress;
@@ -7362,7 +7732,8 @@ struct ChartGroupComputeChartsTaskGroupArgs {
ThreadLocal<PiecewiseParam> *piecewiseParam;
};
-static void runChartGroupComputeChartsTask(void *groupUserData, void *taskUserData) {
+static void runChartGroupComputeChartsTask(void *groupUserData, void *taskUserData)
+{
auto args = (ChartGroupComputeChartsTaskGroupArgs *)groupUserData;
auto chartGroup = (ChartGroup *)taskUserData;
if (args->progress->cancel)
@@ -7372,7 +7743,8 @@ static void runChartGroupComputeChartsTask(void *groupUserData, void *taskUserDa
XA_PROFILE_END(chartGroupComputeChartsThread)
}
-struct MeshComputeChartsTaskGroupArgs {
+struct MeshComputeChartsTaskGroupArgs
+{
ThreadLocal<segment::Atlas> *atlas;
const ChartOptions *options;
Progress *progress;
@@ -7382,7 +7754,8 @@ struct MeshComputeChartsTaskGroupArgs {
ThreadLocal<PiecewiseParam> *piecewiseParam;
};
-struct MeshComputeChartsTaskArgs {
+struct MeshComputeChartsTaskArgs
+{
const Mesh *sourceMesh;
Array<ChartGroup *> *chartGroups; // output
InvalidMeshGeometry *invalidMeshGeometry; // output
@@ -7392,7 +7765,8 @@ struct MeshComputeChartsTaskArgs {
static uint32_t s_faceGroupsCurrentVertex = 0;
#endif
-static void runMeshComputeChartsTask(void *groupUserData, void *taskUserData) {
+static void runMeshComputeChartsTask(void *groupUserData, void *taskUserData)
+{
auto groupArgs = (MeshComputeChartsTaskGroupArgs *)groupUserData;
auto args = (MeshComputeChartsTaskArgs *)taskUserData;
if (groupArgs->progress->cancel)
@@ -7491,12 +7865,13 @@ cleanup:
}
/// An atlas is a set of chart groups.
-class Atlas {
+class Atlas
+{
public:
- Atlas() :
- m_chartsComputed(false) {}
+ Atlas() : m_chartsComputed(false) {}
- ~Atlas() {
+ ~Atlas()
+ {
for (uint32_t i = 0; i < m_meshChartGroups.size(); i++) {
for (uint32_t j = 0; j < m_meshChartGroups[i].size(); j++) {
m_meshChartGroups[i][j]->~ChartGroup();
@@ -7513,11 +7888,13 @@ public:
uint32_t chartGroupCount(uint32_t mesh) const { return m_meshChartGroups[mesh].size(); }
const ChartGroup *chartGroupAt(uint32_t mesh, uint32_t group) const { return m_meshChartGroups[mesh][group]; }
- void addMesh(const Mesh *mesh) {
+ void addMesh(const Mesh *mesh)
+ {
m_meshes.push_back(mesh);
}
- bool computeCharts(TaskScheduler *taskScheduler, const ChartOptions &options, ProgressFunc progressFunc, void *progressUserData) {
+ bool computeCharts(TaskScheduler *taskScheduler, const ChartOptions &options, ProgressFunc progressFunc, void *progressUserData)
+ {
XA_PROFILE_START(computeChartsReal)
#if XA_DEBUG_EXPORT_OBJ_PLANAR_REGIONS
segment::s_planarRegionsCurrentRegion = segment::s_planarRegionsCurrentVertex = 0;
@@ -7591,7 +7968,7 @@ public:
private:
Array<const Mesh *> m_meshes;
Array<InvalidMeshGeometry> m_invalidMeshGeometry; // 1 per mesh.
- Array<Array<ChartGroup *>> m_meshChartGroups;
+ Array<Array<ChartGroup *> > m_meshChartGroups;
bool m_chartsComputed;
};
@@ -7599,15 +7976,17 @@ private:
namespace pack {
-class AtlasImage {
+class AtlasImage
+{
public:
- AtlasImage(uint32_t width, uint32_t height) :
- m_width(width), m_height(height) {
+ AtlasImage(uint32_t width, uint32_t height) : m_width(width), m_height(height)
+ {
m_data.resize(m_width * m_height);
memset(m_data.data(), 0, sizeof(uint32_t) * m_data.size());
}
- void resize(uint32_t width, uint32_t height) {
+ void resize(uint32_t width, uint32_t height)
+ {
Array<uint32_t> data;
data.resize(width * height);
memset(data.data(), 0, sizeof(uint32_t) * data.size());
@@ -7618,7 +7997,8 @@ public:
data.moveTo(m_data);
}
- void addChart(uint32_t chartIndex, const BitImage *image, const BitImage *imageBilinear, const BitImage *imagePadding, int atlas_w, int atlas_h, int offset_x, int offset_y) {
+ void addChart(uint32_t chartIndex, const BitImage *image, const BitImage *imageBilinear, const BitImage *imagePadding, int atlas_w, int atlas_h, int offset_x, int offset_y)
+ {
const int w = image->width();
const int h = image->height();
for (int y = 0; y < h; y++) {
@@ -7644,13 +8024,15 @@ public:
}
}
- void copyTo(uint32_t *dest, uint32_t destWidth, uint32_t destHeight, int padding) const {
+ void copyTo(uint32_t *dest, uint32_t destWidth, uint32_t destHeight, int padding) const
+ {
for (uint32_t y = 0; y < destHeight; y++)
memcpy(&dest[y * destWidth], &m_data[padding + (y + padding) * m_width], destWidth * sizeof(uint32_t));
}
#if XA_DEBUG_EXPORT_ATLAS_IMAGES
- void writeTga(const char *filename, uint32_t width, uint32_t height) const {
+ void writeTga(const char *filename, uint32_t width, uint32_t height) const
+ {
Array<uint8_t> image;
image.resize(width * height * 3);
for (uint32_t y = 0; y < height; y++) {
@@ -7692,7 +8074,8 @@ private:
Array<uint32_t> m_data;
};
-struct Chart {
+struct Chart
+{
int32_t atlasIndex;
uint32_t material;
ConstArrayView<uint32_t> indices;
@@ -7711,12 +8094,14 @@ struct Chart {
uint32_t uniqueVertexCount() const { return uniqueVertices.isEmpty() ? vertices.length : uniqueVertices.size(); }
};
-struct AddChartTaskArgs {
+struct AddChartTaskArgs
+{
param::Chart *paramChart;
Chart *chart; // out
};
-static void runAddChartTask(void *groupUserData, void *taskUserData) {
+static void runAddChartTask(void *groupUserData, void *taskUserData)
+{
XA_PROFILE_START(packChartsAddChartsThread)
auto boundingBox = (ThreadLocal<BoundingBox2D> *)groupUserData;
auto args = (AddChartTaskArgs *)taskUserData;
@@ -7753,8 +8138,10 @@ static void runAddChartTask(void *groupUserData, void *taskUserData) {
XA_PROFILE_END(packChartsAddChartsThread)
}
-struct Atlas {
- ~Atlas() {
+struct Atlas
+{
+ ~Atlas()
+ {
for (uint32_t i = 0; i < m_atlasImages.size(); i++) {
m_atlasImages[i]->~AtlasImage();
XA_FREE(m_atlasImages[i]);
@@ -7778,7 +8165,8 @@ struct Atlas {
const Array<AtlasImage *> &getImages() const { return m_atlasImages; }
float getUtilization(uint32_t atlas) const { return m_utilization[atlas]; }
- void addCharts(TaskScheduler *taskScheduler, param::Atlas *paramAtlas) {
+ void addCharts(TaskScheduler *taskScheduler, param::Atlas *paramAtlas)
+ {
// Count charts.
uint32_t chartCount = 0;
for (uint32_t i = 0; i < paramAtlas->meshCount(); i++) {
@@ -7819,7 +8207,8 @@ struct Atlas {
m_charts[i] = taskArgs[i].chart;
}
- void addUvMeshCharts(UvMeshInstance *mesh) {
+ void addUvMeshCharts(UvMeshInstance *mesh)
+ {
// Copy texcoords from mesh.
mesh->texcoords.resize(mesh->mesh->texcoords.size());
memcpy(mesh->texcoords.data(), mesh->mesh->texcoords.data(), mesh->texcoords.size() * sizeof(Vector2));
@@ -7882,7 +8271,8 @@ struct Atlas {
}
// Pack charts in the smallest possible rectangle.
- bool packCharts(const PackOptions &options, ProgressFunc progressFunc, void *progressUserData) {
+ bool packCharts(const PackOptions &options, ProgressFunc progressFunc, void *progressUserData)
+ {
if (progressFunc) {
if (!progressFunc(ProgressCategory::PackCharts, 0, progressUserData))
return false;
@@ -8116,7 +8506,8 @@ struct Atlas {
int best_x = 0, best_y = 0;
int best_cw = 0, best_ch = 0;
int best_r = 0;
- for (;;) {
+ for (;;)
+ {
#if XA_DEBUG
bool firstChartInBitImage = false;
#endif
@@ -8152,7 +8543,8 @@ struct Atlas {
if (best_x + best_cw > atlasSizes[currentAtlas].x || best_y + best_ch > atlasSizes[currentAtlas].y) {
for (uint32_t j = 0; j < chartStartPositions.size(); j++)
chartStartPositions[j] = Vector2i(0, 0);
- } else {
+ }
+ else {
chartStartPositions[currentAtlas] = Vector2i(best_x, best_y);
}
}
@@ -8240,7 +8632,8 @@ struct Atlas {
}
if (m_utilization.size() > 1) {
XA_PRINT(" %u: %f%% utilization\n", i, m_utilization[i] * 100.0f);
- } else {
+ }
+ else {
XA_PRINT(" %f%% utilization\n", m_utilization[i] * 100.0f);
}
}
@@ -8259,14 +8652,16 @@ struct Atlas {
}
private:
- bool findChartLocation(const PackOptions &options, const Vector2i &startPosition, const BitImage *atlasBitImage, const BitImage *chartBitImage, const BitImage *chartBitImageRotated, int w, int h, int *best_x, int *best_y, int *best_w, int *best_h, int *best_r, uint32_t maxResolution) {
+ bool findChartLocation(const PackOptions &options, const Vector2i &startPosition, const BitImage *atlasBitImage, const BitImage *chartBitImage, const BitImage *chartBitImageRotated, int w, int h, int *best_x, int *best_y, int *best_w, int *best_h, int *best_r, uint32_t maxResolution)
+ {
const int attempts = 4096;
if (options.bruteForce || attempts >= w * h)
return findChartLocation_bruteForce(options, startPosition, atlasBitImage, chartBitImage, chartBitImageRotated, w, h, best_x, best_y, best_w, best_h, best_r, maxResolution);
return findChartLocation_random(options, atlasBitImage, chartBitImage, chartBitImageRotated, w, h, best_x, best_y, best_w, best_h, best_r, attempts, maxResolution);
}
- bool findChartLocation_bruteForce(const PackOptions &options, const Vector2i &startPosition, const BitImage *atlasBitImage, const BitImage *chartBitImage, const BitImage *chartBitImageRotated, int w, int h, int *best_x, int *best_y, int *best_w, int *best_h, int *best_r, uint32_t maxResolution) {
+ bool findChartLocation_bruteForce(const PackOptions &options, const Vector2i &startPosition, const BitImage *atlasBitImage, const BitImage *chartBitImage, const BitImage *chartBitImageRotated, int w, int h, int *best_x, int *best_y, int *best_w, int *best_h, int *best_r, uint32_t maxResolution)
+ {
const int stepSize = options.blockAlign ? 4 : 1;
int best_metric = INT_MAX;
// Try two different orientations.
@@ -8311,7 +8706,8 @@ private:
return best_metric != INT_MAX;
}
- bool findChartLocation_random(const PackOptions &options, const BitImage *atlasBitImage, const BitImage *chartBitImage, const BitImage *chartBitImageRotated, int w, int h, int *best_x, int *best_y, int *best_w, int *best_h, int *best_r, int attempts, uint32_t maxResolution) {
+ bool findChartLocation_random(const PackOptions &options, const BitImage *atlasBitImage, const BitImage *chartBitImage, const BitImage *chartBitImageRotated, int w, int h, int *best_x, int *best_y, int *best_w, int *best_h, int *best_r, int attempts, uint32_t maxResolution)
+ {
bool result = false;
const int BLOCK_SIZE = 4;
int best_metric = INT_MAX;
@@ -8366,7 +8762,8 @@ private:
return result;
}
- void addChart(BitImage *atlasBitImage, const BitImage *chartBitImage, const BitImage *chartBitImageRotated, int atlas_w, int atlas_h, int offset_x, int offset_y, int r) {
+ void addChart(BitImage *atlasBitImage, const BitImage *chartBitImage, const BitImage *chartBitImageRotated, int atlas_w, int atlas_h, int offset_x, int offset_y, int r)
+ {
XA_DEBUG_ASSERT(r == 0 || r == 1);
const BitImage *image = r == 0 ? chartBitImage : chartBitImageRotated;
const int w = image->width();
@@ -8389,7 +8786,8 @@ private:
}
}
- void bilinearExpand(const Chart *chart, BitImage *source, BitImage *dest, BitImage *destRotated, UniformGrid2 &boundaryEdgeGrid) const {
+ void bilinearExpand(const Chart *chart, BitImage *source, BitImage *dest, BitImage *destRotated, UniformGrid2 &boundaryEdgeGrid) const
+ {
boundaryEdgeGrid.reset(chart->vertices, chart->indices);
if (chart->boundaryEdges) {
const uint32_t edgeCount = chart->boundaryEdges->size();
@@ -8444,11 +8842,13 @@ private:
}
}
- struct DrawTriangleCallbackArgs {
+ struct DrawTriangleCallbackArgs
+ {
BitImage *chartBitImage, *chartBitImageRotated;
};
- static bool drawTriangleCallback(void *param, int x, int y) {
+ static bool drawTriangleCallback(void *param, int x, int y)
+ {
auto args = (DrawTriangleCallbackArgs *)param;
args->chartBitImage->set(x, y);
if (args->chartBitImageRotated)
@@ -8471,13 +8871,15 @@ private:
} // namespace internal
// Used to map triangulated polygons back to polygons.
-struct MeshPolygonMapping {
+struct MeshPolygonMapping
+{
internal::Array<uint8_t> faceVertexCount; // Copied from MeshDecl::faceVertexCount.
internal::Array<uint32_t> triangleToPolygonMap; // Triangle index (mesh face index) to polygon index.
internal::Array<uint32_t> triangleToPolygonIndicesMap; // Triangle indices to polygon indices.
};
-struct Context {
+struct Context
+{
Atlas atlas;
internal::Progress *addMeshProgress = nullptr;
internal::TaskGroupHandle addMeshTaskGroup;
@@ -8492,14 +8894,16 @@ struct Context {
bool uvMeshChartsComputed = false;
};
-Atlas *Create() {
+Atlas *Create()
+{
Context *ctx = XA_NEW(internal::MemTag::Default, Context);
memset(&ctx->atlas, 0, sizeof(Atlas));
ctx->taskScheduler = XA_NEW(internal::MemTag::Default, internal::TaskScheduler);
return &ctx->atlas;
}
-static void DestroyOutputMeshes(Context *ctx) {
+static void DestroyOutputMeshes(Context *ctx)
+{
if (!ctx->atlas.meshes)
return;
for (int i = 0; i < (int)ctx->atlas.meshCount; i++) {
@@ -8520,7 +8924,8 @@ static void DestroyOutputMeshes(Context *ctx) {
ctx->atlas.meshes = nullptr;
}
-void Destroy(Atlas *atlas) {
+void Destroy(Atlas *atlas)
+{
XA_DEBUG_ASSERT(atlas);
Context *ctx = (Context *)atlas;
if (atlas->utilization)
@@ -8567,14 +8972,15 @@ void Destroy(Atlas *atlas) {
#endif
}
-static void runAddMeshTask(void *groupUserData, void *taskUserData) {
+static void runAddMeshTask(void *groupUserData, void *taskUserData)
+{
XA_PROFILE_START(addMeshThread)
auto ctx = (Context *)groupUserData;
auto mesh = (internal::Mesh *)taskUserData;
internal::Progress *progress = ctx->addMeshProgress;
if (progress->cancel) {
XA_PROFILE_END(addMeshThread)
- return;
+ return;
}
XA_PROFILE_START(addMeshCreateColocals)
mesh->createColocals();
@@ -8587,32 +8993,37 @@ static void runAddMeshTask(void *groupUserData, void *taskUserData) {
XA_PROFILE_END(addMeshThread)
}
-static internal::Vector3 DecodePosition(const MeshDecl &meshDecl, uint32_t index) {
+static internal::Vector3 DecodePosition(const MeshDecl &meshDecl, uint32_t index)
+{
XA_DEBUG_ASSERT(meshDecl.vertexPositionData);
XA_DEBUG_ASSERT(meshDecl.vertexPositionStride > 0);
return *((const internal::Vector3 *)&((const uint8_t *)meshDecl.vertexPositionData)[meshDecl.vertexPositionStride * index]);
}
-static internal::Vector3 DecodeNormal(const MeshDecl &meshDecl, uint32_t index) {
+static internal::Vector3 DecodeNormal(const MeshDecl &meshDecl, uint32_t index)
+{
XA_DEBUG_ASSERT(meshDecl.vertexNormalData);
XA_DEBUG_ASSERT(meshDecl.vertexNormalStride > 0);
return *((const internal::Vector3 *)&((const uint8_t *)meshDecl.vertexNormalData)[meshDecl.vertexNormalStride * index]);
}
-static internal::Vector2 DecodeUv(const MeshDecl &meshDecl, uint32_t index) {
+static internal::Vector2 DecodeUv(const MeshDecl &meshDecl, uint32_t index)
+{
XA_DEBUG_ASSERT(meshDecl.vertexUvData);
XA_DEBUG_ASSERT(meshDecl.vertexUvStride > 0);
return *((const internal::Vector2 *)&((const uint8_t *)meshDecl.vertexUvData)[meshDecl.vertexUvStride * index]);
}
-static uint32_t DecodeIndex(IndexFormat format, const void *indexData, int32_t offset, uint32_t i) {
+static uint32_t DecodeIndex(IndexFormat format, const void *indexData, int32_t offset, uint32_t i)
+{
XA_DEBUG_ASSERT(indexData);
if (format == IndexFormat::UInt16)
return uint16_t((int32_t)((const uint16_t *)indexData)[i] + offset);
return uint32_t((int32_t)((const uint32_t *)indexData)[i] + offset);
}
-AddMeshError AddMesh(Atlas *atlas, const MeshDecl &meshDecl, uint32_t meshCountHint) {
+AddMeshError AddMesh(Atlas *atlas, const MeshDecl &meshDecl, uint32_t meshCountHint)
+{
XA_DEBUG_ASSERT(atlas);
if (!atlas) {
XA_PRINT_WARNING("AddMesh: atlas is null.\n");
@@ -8630,7 +9041,8 @@ AddMeshError AddMesh(Atlas *atlas, const MeshDecl &meshDecl, uint32_t meshCountH
// Don't know how many times AddMesh will be called, so progress needs to adjusted each time.
if (!ctx->addMeshProgress) {
ctx->addMeshProgress = XA_NEW_ARGS(internal::MemTag::Default, internal::Progress, ProgressCategory::AddMesh, ctx->progressFunc, ctx->progressUserData, 1);
- } else {
+ }
+ else {
ctx->addMeshProgress->setMaxValue(internal::max(ctx->meshes.size() + 1, meshCountHint));
}
XA_PROFILE_START(addMeshCopyData)
@@ -8804,7 +9216,8 @@ AddMeshError AddMesh(Atlas *atlas, const MeshDecl &meshDecl, uint32_t meshCountH
return AddMeshError::Success;
}
-void AddMeshJoin(Atlas *atlas) {
+void AddMeshJoin(Atlas *atlas)
+{
XA_DEBUG_ASSERT(atlas);
if (!atlas) {
XA_PRINT_WARNING("AddMeshJoin: atlas is null.\n");
@@ -8847,7 +9260,8 @@ void AddMeshJoin(Atlas *atlas) {
}
}
-AddMeshError AddUvMesh(Atlas *atlas, const UvMeshDecl &decl) {
+AddMeshError AddUvMesh(Atlas *atlas, const UvMeshDecl &decl)
+{
XA_DEBUG_ASSERT(atlas);
if (!atlas) {
XA_PRINT_WARNING("AddUvMesh: atlas is null.\n");
@@ -8948,7 +9362,8 @@ AddMeshError AddUvMesh(Atlas *atlas, const UvMeshDecl &decl) {
return AddMeshError::Success;
}
-void ComputeCharts(Atlas *atlas, ChartOptions options) {
+void ComputeCharts(Atlas *atlas, ChartOptions options)
+{
if (!atlas) {
XA_PRINT_WARNING("ComputeCharts: atlas is null.\n");
return;
@@ -9136,7 +9551,8 @@ void ComputeCharts(Atlas *atlas, ChartOptions options) {
XA_PRINT_MEM_USAGE
}
-void PackCharts(Atlas *atlas, PackOptions packOptions) {
+void PackCharts(Atlas *atlas, PackOptions packOptions)
+{
// Validate arguments and context state.
if (!atlas) {
XA_PRINT_WARNING("PackCharts: atlas is null.\n");
@@ -9177,7 +9593,8 @@ void PackCharts(Atlas *atlas, PackOptions packOptions) {
if (!ctx->uvMeshInstances.isEmpty()) {
for (uint32_t i = 0; i < ctx->uvMeshInstances.size(); i++)
packAtlas.addUvMeshCharts(ctx->uvMeshInstances[i]);
- } else
+ }
+ else
packAtlas.addCharts(ctx->taskScheduler, &ctx->paramAtlas);
XA_PROFILE_END(packChartsAddCharts)
XA_PROFILE_START(packCharts)
@@ -9455,7 +9872,8 @@ void PackCharts(Atlas *atlas, PackOptions packOptions) {
XA_PRINT_MEM_USAGE
}
-void Generate(Atlas *atlas, ChartOptions chartOptions, PackOptions packOptions) {
+void Generate(Atlas *atlas, ChartOptions chartOptions, PackOptions packOptions)
+{
if (!atlas) {
XA_PRINT_WARNING("Generate: atlas is null.\n");
return;
@@ -9469,7 +9887,8 @@ void Generate(Atlas *atlas, ChartOptions chartOptions, PackOptions packOptions)
PackCharts(atlas, packOptions);
}
-void SetProgressCallback(Atlas *atlas, ProgressFunc progressFunc, void *progressUserData) {
+void SetProgressCallback(Atlas *atlas, ProgressFunc progressFunc, void *progressUserData)
+{
if (!atlas) {
XA_PRINT_WARNING("SetProgressCallback: atlas is null.\n");
return;
@@ -9479,17 +9898,20 @@ void SetProgressCallback(Atlas *atlas, ProgressFunc progressFunc, void *progress
ctx->progressUserData = progressUserData;
}
-void SetAlloc(ReallocFunc reallocFunc, FreeFunc freeFunc) {
+void SetAlloc(ReallocFunc reallocFunc, FreeFunc freeFunc)
+{
internal::s_realloc = reallocFunc;
internal::s_free = freeFunc;
}
-void SetPrint(PrintFunc print, bool verbose) {
+void SetPrint(PrintFunc print, bool verbose)
+{
internal::s_print = print;
internal::s_printVerbose = verbose;
}
-const char *StringForEnum(AddMeshError error) {
+const char *StringForEnum(AddMeshError error)
+{
if (error == AddMeshError::Error)
return "Unspecified error";
if (error == AddMeshError::IndexOutOfRange)
@@ -9501,7 +9923,8 @@ const char *StringForEnum(AddMeshError error) {
return "Success";
}
-const char *StringForEnum(ProgressCategory category) {
+const char *StringForEnum(ProgressCategory category)
+{
if (category == ProgressCategory::AddMesh)
return "Adding mesh(es)";
if (category == ProgressCategory::ComputeCharts)
@@ -9529,76 +9952,93 @@ static_assert(sizeof(xatlas::PackOptions) == sizeof(xatlasPackOptions), "xatlasP
extern "C" {
#endif
-xatlasAtlas *xatlasCreate() {
+xatlasAtlas *xatlasCreate()
+{
return (xatlasAtlas *)xatlas::Create();
}
-void xatlasDestroy(xatlasAtlas *atlas) {
+void xatlasDestroy(xatlasAtlas *atlas)
+{
xatlas::Destroy((xatlas::Atlas *)atlas);
}
-xatlasAddMeshError xatlasAddMesh(xatlasAtlas *atlas, const xatlasMeshDecl *meshDecl, uint32_t meshCountHint) {
+xatlasAddMeshError xatlasAddMesh(xatlasAtlas *atlas, const xatlasMeshDecl *meshDecl, uint32_t meshCountHint)
+{
return (xatlasAddMeshError)xatlas::AddMesh((xatlas::Atlas *)atlas, *(const xatlas::MeshDecl *)meshDecl, meshCountHint);
}
-void xatlasAddMeshJoin(xatlasAtlas *atlas) {
+void xatlasAddMeshJoin(xatlasAtlas *atlas)
+{
xatlas::AddMeshJoin((xatlas::Atlas *)atlas);
}
-xatlasAddMeshError xatlasAddUvMesh(xatlasAtlas *atlas, const xatlasUvMeshDecl *decl) {
+xatlasAddMeshError xatlasAddUvMesh(xatlasAtlas *atlas, const xatlasUvMeshDecl *decl)
+{
return (xatlasAddMeshError)xatlas::AddUvMesh((xatlas::Atlas *)atlas, *(const xatlas::UvMeshDecl *)decl);
}
-void xatlasComputeCharts(xatlasAtlas *atlas, const xatlasChartOptions *chartOptions) {
+void xatlasComputeCharts(xatlasAtlas *atlas, const xatlasChartOptions *chartOptions)
+{
xatlas::ComputeCharts((xatlas::Atlas *)atlas, chartOptions ? *(xatlas::ChartOptions *)chartOptions : xatlas::ChartOptions());
}
-void xatlasPackCharts(xatlasAtlas *atlas, const xatlasPackOptions *packOptions) {
+void xatlasPackCharts(xatlasAtlas *atlas, const xatlasPackOptions *packOptions)
+{
xatlas::PackCharts((xatlas::Atlas *)atlas, packOptions ? *(xatlas::PackOptions *)packOptions : xatlas::PackOptions());
}
-void xatlasGenerate(xatlasAtlas *atlas, const xatlasChartOptions *chartOptions, const xatlasPackOptions *packOptions) {
+void xatlasGenerate(xatlasAtlas *atlas, const xatlasChartOptions *chartOptions, const xatlasPackOptions *packOptions)
+{
xatlas::Generate((xatlas::Atlas *)atlas, chartOptions ? *(xatlas::ChartOptions *)chartOptions : xatlas::ChartOptions(), packOptions ? *(xatlas::PackOptions *)packOptions : xatlas::PackOptions());
}
-void xatlasSetProgressCallback(xatlasAtlas *atlas, xatlasProgressFunc progressFunc, void *progressUserData) {
+void xatlasSetProgressCallback(xatlasAtlas *atlas, xatlasProgressFunc progressFunc, void *progressUserData)
+{
xatlas::ProgressFunc pf;
*(void **)&pf = (void *)progressFunc;
xatlas::SetProgressCallback((xatlas::Atlas *)atlas, pf, progressUserData);
}
-void xatlasSetAlloc(xatlasReallocFunc reallocFunc, xatlasFreeFunc freeFunc) {
+void xatlasSetAlloc(xatlasReallocFunc reallocFunc, xatlasFreeFunc freeFunc)
+{
xatlas::SetAlloc((xatlas::ReallocFunc)reallocFunc, (xatlas::FreeFunc)freeFunc);
}
-void xatlasSetPrint(xatlasPrintFunc print, bool verbose) {
+void xatlasSetPrint(xatlasPrintFunc print, bool verbose)
+{
xatlas::SetPrint((xatlas::PrintFunc)print, verbose);
}
-const char *xatlasAddMeshErrorString(xatlasAddMeshError error) {
+const char *xatlasAddMeshErrorString(xatlasAddMeshError error)
+{
return xatlas::StringForEnum((xatlas::AddMeshError)error);
}
-const char *xatlasProgressCategoryString(xatlasProgressCategory category) {
+const char *xatlasProgressCategoryString(xatlasProgressCategory category)
+{
return xatlas::StringForEnum((xatlas::ProgressCategory)category);
}
-void xatlasMeshDeclInit(xatlasMeshDecl *meshDecl) {
+void xatlasMeshDeclInit(xatlasMeshDecl *meshDecl)
+{
xatlas::MeshDecl init;
memcpy(meshDecl, &init, sizeof(init));
}
-void xatlasUvMeshDeclInit(xatlasUvMeshDecl *uvMeshDecl) {
+void xatlasUvMeshDeclInit(xatlasUvMeshDecl *uvMeshDecl)
+{
xatlas::UvMeshDecl init;
memcpy(uvMeshDecl, &init, sizeof(init));
}
-void xatlasChartOptionsInit(xatlasChartOptions *chartOptions) {
+void xatlasChartOptionsInit(xatlasChartOptions *chartOptions)
+{
xatlas::ChartOptions init;
memcpy(chartOptions, &init, sizeof(init));
}
-void xatlasPackOptionsInit(xatlasPackOptions *packOptions) {
+void xatlasPackOptionsInit(xatlasPackOptions *packOptions)
+{
xatlas::PackOptions init;
memcpy(packOptions, &init, sizeof(init));
}
diff --git a/thirdparty/xatlas/xatlas.h b/thirdparty/xatlas/xatlas.h
index fc40d9d49c..d66a96db21 100644
--- a/thirdparty/xatlas/xatlas.h
+++ b/thirdparty/xatlas/xatlas.h
@@ -36,7 +36,8 @@ Copyright NVIDIA Corporation 2006 -- Ignacio Castano <icastano@nvidia.com>
namespace xatlas {
-enum class ChartType {
+enum class ChartType
+{
Planar,
Ortho,
LSCM,
@@ -45,7 +46,8 @@ enum class ChartType {
};
// A group of connected faces, belonging to a single atlas.
-struct Chart {
+struct Chart
+{
uint32_t *faceArray;
uint32_t atlasIndex; // Sub-atlas index.
uint32_t faceCount;
@@ -54,7 +56,8 @@ struct Chart {
};
// Output vertex.
-struct Vertex {
+struct Vertex
+{
int32_t atlasIndex; // Sub-atlas index. -1 if the vertex doesn't exist in any atlas.
int32_t chartIndex; // -1 if the vertex doesn't exist in any chart.
float uv[2]; // Not normalized - values are in Atlas width and height range.
@@ -62,7 +65,8 @@ struct Vertex {
};
// Output mesh.
-struct Mesh {
+struct Mesh
+{
Chart *chartArray;
uint32_t *indexArray;
Vertex *vertexArray;
@@ -77,7 +81,8 @@ static const uint32_t kImageIsBilinearBit = 0x40000000;
static const uint32_t kImageIsPaddingBit = 0x20000000;
// Empty on creation. Populated after charts are packed.
-struct Atlas {
+struct Atlas
+{
uint32_t *image;
Mesh *meshes; // The output meshes, corresponding to each AddMesh call.
float *utilization; // Normalized atlas texel utilization array. E.g. a value of 0.8 means 20% empty space. atlasCount in length.
@@ -94,13 +99,15 @@ Atlas *Create();
void Destroy(Atlas *atlas);
-enum class IndexFormat {
+enum class IndexFormat
+{
UInt16,
UInt32
};
// Input mesh declaration.
-struct MeshDecl {
+struct MeshDecl
+{
const void *vertexPositionData = nullptr;
const void *vertexNormalData = nullptr; // optional
const void *vertexUvData = nullptr; // optional. The input UVs are provided as a hint to the chart generator.
@@ -131,7 +138,8 @@ struct MeshDecl {
float epsilon = 1.192092896e-07F;
};
-enum class AddMeshError {
+enum class AddMeshError
+{
Success, // No error.
Error, // Unspecified error.
IndexOutOfRange, // An index is >= MeshDecl vertexCount.
@@ -145,7 +153,8 @@ AddMeshError AddMesh(Atlas *atlas, const MeshDecl &meshDecl, uint32_t meshCountH
// Wait for AddMesh async processing to finish. ComputeCharts / Generate call this internally.
void AddMeshJoin(Atlas *atlas);
-struct UvMeshDecl {
+struct UvMeshDecl
+{
const void *vertexUvData = nullptr;
const void *indexData = nullptr; // optional
const uint32_t *faceMaterialData = nullptr; // Optional. Overlapping UVs should be assigned a different material. Must be indexCount / 3 in length.
@@ -161,7 +170,8 @@ AddMeshError AddUvMesh(Atlas *atlas, const UvMeshDecl &decl);
// Custom parameterization function. texcoords initial values are an orthogonal parameterization.
typedef void (*ParameterizeFunc)(const float *positions, float *texcoords, uint32_t vertexCount, const uint32_t *indices, uint32_t indexCount);
-struct ChartOptions {
+struct ChartOptions
+{
ParameterizeFunc paramFunc = nullptr;
float maxChartArea = 0.0f; // Don't grow charts to be larger than this. 0 means no limit.
@@ -184,7 +194,8 @@ struct ChartOptions {
// Call after all AddMesh calls. Can be called multiple times to recompute charts with different options.
void ComputeCharts(Atlas *atlas, ChartOptions options = ChartOptions());
-struct PackOptions {
+struct PackOptions
+{
// Charts larger than this will be scaled down. 0 means no limit.
uint32_t maxChartSize = 0;
@@ -227,7 +238,8 @@ void PackCharts(Atlas *atlas, PackOptions packOptions = PackOptions());
void Generate(Atlas *atlas, ChartOptions chartOptions = ChartOptions(), PackOptions packOptions = PackOptions());
// Progress tracking.
-enum class ProgressCategory {
+enum class ProgressCategory
+{
AddMesh,
ComputeCharts,
PackCharts,
diff --git a/thirdparty/zstd/common/bitstream.h b/thirdparty/zstd/common/bitstream.h
index d9a2730104..2e5a933ad3 100644
--- a/thirdparty/zstd/common/bitstream.h
+++ b/thirdparty/zstd/common/bitstream.h
@@ -1,7 +1,7 @@
/* ******************************************************************
* bitstream
* Part of FSE library
- * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
*
* You can contact the author at :
* - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
diff --git a/thirdparty/zstd/common/compiler.h b/thirdparty/zstd/common/compiler.h
index 3e454f38c1..a951d0adea 100644
--- a/thirdparty/zstd/common/compiler.h
+++ b/thirdparty/zstd/common/compiler.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
@@ -90,6 +90,7 @@
# endif
#endif
+
/* target attribute */
#ifndef __has_attribute
#define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
diff --git a/thirdparty/zstd/common/cpu.h b/thirdparty/zstd/common/cpu.h
index cb210593ea..8acd33be3c 100644
--- a/thirdparty/zstd/common/cpu.h
+++ b/thirdparty/zstd/common/cpu.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2020, Facebook, Inc.
+ * Copyright (c) Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
diff --git a/thirdparty/zstd/common/debug.c b/thirdparty/zstd/common/debug.c
index f303f4a2e5..bb863c9ea6 100644
--- a/thirdparty/zstd/common/debug.c
+++ b/thirdparty/zstd/common/debug.c
@@ -1,7 +1,7 @@
/* ******************************************************************
* debug
* Part of FSE library
- * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
*
* You can contact the author at :
* - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
diff --git a/thirdparty/zstd/common/debug.h b/thirdparty/zstd/common/debug.h
index 8b5734366c..3b2a320a18 100644
--- a/thirdparty/zstd/common/debug.h
+++ b/thirdparty/zstd/common/debug.h
@@ -1,7 +1,7 @@
/* ******************************************************************
* debug
* Part of FSE library
- * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
*
* You can contact the author at :
* - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
diff --git a/thirdparty/zstd/common/entropy_common.c b/thirdparty/zstd/common/entropy_common.c
index f9fcb1acfc..41cd69566b 100644
--- a/thirdparty/zstd/common/entropy_common.c
+++ b/thirdparty/zstd/common/entropy_common.c
@@ -1,6 +1,6 @@
/* ******************************************************************
* Common functions of New Generation Entropy library
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
*
* You can contact the author at :
* - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
diff --git a/thirdparty/zstd/common/error_private.c b/thirdparty/zstd/common/error_private.c
index 45bba5305b..6d1135f8c3 100644
--- a/thirdparty/zstd/common/error_private.c
+++ b/thirdparty/zstd/common/error_private.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
diff --git a/thirdparty/zstd/common/error_private.h b/thirdparty/zstd/common/error_private.h
index 71b37b8dfa..6d8b9f7763 100644
--- a/thirdparty/zstd/common/error_private.h
+++ b/thirdparty/zstd/common/error_private.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
@@ -21,8 +21,8 @@ extern "C" {
/* ****************************************
* Dependencies
******************************************/
-#include "zstd_deps.h" /* size_t */
-#include "zstd_errors.h" /* enum list */
+#include "../zstd_errors.h" /* enum list */
+#include "zstd_deps.h" /* size_t */
/* ****************************************
diff --git a/thirdparty/zstd/common/fse.h b/thirdparty/zstd/common/fse.h
index dd5fc44e80..19dd4febcd 100644
--- a/thirdparty/zstd/common/fse.h
+++ b/thirdparty/zstd/common/fse.h
@@ -1,7 +1,7 @@
/* ******************************************************************
* FSE : Finite State Entropy codec
* Public Prototypes declaration
- * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
*
* You can contact the author at :
* - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
@@ -352,7 +352,7 @@ size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits);
size_t FSE_buildDTable_rle (FSE_DTable* dt, unsigned char symbolValue);
/**< build a fake FSE_DTable, designed to always generate the same symbolValue */
-#define FSE_DECOMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) (FSE_DTABLE_SIZE_U32(maxTableLog) + FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxTableLog, maxSymbolValue))
+#define FSE_DECOMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) (FSE_DTABLE_SIZE_U32(maxTableLog) + FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) + (FSE_MAX_SYMBOL_VALUE + 1) / 2 + 1)
#define FSE_DECOMPRESS_WKSP_SIZE(maxTableLog, maxSymbolValue) (FSE_DECOMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) * sizeof(unsigned))
size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize);
/**< same as FSE_decompress(), using an externally allocated `workSpace` produced with `FSE_DECOMPRESS_WKSP_SIZE_U32(maxLog, maxSymbolValue)` */
diff --git a/thirdparty/zstd/common/fse_decompress.c b/thirdparty/zstd/common/fse_decompress.c
index c164430f99..f4ff58fa0a 100644
--- a/thirdparty/zstd/common/fse_decompress.c
+++ b/thirdparty/zstd/common/fse_decompress.c
@@ -1,6 +1,6 @@
/* ******************************************************************
* FSE : Finite State Entropy decoder
- * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
*
* You can contact the author at :
* - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
@@ -310,6 +310,12 @@ size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size
return FSE_decompress_wksp_bmi2(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize, /* bmi2 */ 0);
}
+typedef struct {
+ short ncount[FSE_MAX_SYMBOL_VALUE + 1];
+ FSE_DTable dtable[1]; /* Dynamically sized */
+} FSE_DecompressWksp;
+
+
FORCE_INLINE_TEMPLATE size_t FSE_decompress_wksp_body(
void* dst, size_t dstCapacity,
const void* cSrc, size_t cSrcSize,
@@ -318,33 +324,37 @@ FORCE_INLINE_TEMPLATE size_t FSE_decompress_wksp_body(
{
const BYTE* const istart = (const BYTE*)cSrc;
const BYTE* ip = istart;
- short counting[FSE_MAX_SYMBOL_VALUE+1];
unsigned tableLog;
unsigned maxSymbolValue = FSE_MAX_SYMBOL_VALUE;
- FSE_DTable* const dtable = (FSE_DTable*)workSpace;
+ FSE_DecompressWksp* const wksp = (FSE_DecompressWksp*)workSpace;
+
+ DEBUG_STATIC_ASSERT((FSE_MAX_SYMBOL_VALUE + 1) % 2 == 0);
+ if (wkspSize < sizeof(*wksp)) return ERROR(GENERIC);
/* normal FSE decoding mode */
- size_t const NCountLength = FSE_readNCount_bmi2(counting, &maxSymbolValue, &tableLog, istart, cSrcSize, bmi2);
- if (FSE_isError(NCountLength)) return NCountLength;
- if (tableLog > maxLog) return ERROR(tableLog_tooLarge);
- assert(NCountLength <= cSrcSize);
- ip += NCountLength;
- cSrcSize -= NCountLength;
+ {
+ size_t const NCountLength = FSE_readNCount_bmi2(wksp->ncount, &maxSymbolValue, &tableLog, istart, cSrcSize, bmi2);
+ if (FSE_isError(NCountLength)) return NCountLength;
+ if (tableLog > maxLog) return ERROR(tableLog_tooLarge);
+ assert(NCountLength <= cSrcSize);
+ ip += NCountLength;
+ cSrcSize -= NCountLength;
+ }
if (FSE_DECOMPRESS_WKSP_SIZE(tableLog, maxSymbolValue) > wkspSize) return ERROR(tableLog_tooLarge);
- workSpace = dtable + FSE_DTABLE_SIZE_U32(tableLog);
- wkspSize -= FSE_DTABLE_SIZE(tableLog);
+ workSpace = wksp->dtable + FSE_DTABLE_SIZE_U32(tableLog);
+ wkspSize -= sizeof(*wksp) + FSE_DTABLE_SIZE(tableLog);
- CHECK_F( FSE_buildDTable_internal(dtable, counting, maxSymbolValue, tableLog, workSpace, wkspSize) );
+ CHECK_F( FSE_buildDTable_internal(wksp->dtable, wksp->ncount, maxSymbolValue, tableLog, workSpace, wkspSize) );
{
- const void* ptr = dtable;
+ const void* ptr = wksp->dtable;
const FSE_DTableHeader* DTableH = (const FSE_DTableHeader*)ptr;
const U32 fastMode = DTableH->fastMode;
/* select fast mode (static) */
- if (fastMode) return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, dtable, 1);
- return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, dtable, 0);
+ if (fastMode) return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, wksp->dtable, 1);
+ return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, wksp->dtable, 0);
}
}
diff --git a/thirdparty/zstd/common/huf.h b/thirdparty/zstd/common/huf.h
index 1afef90c7c..3d47ced030 100644
--- a/thirdparty/zstd/common/huf.h
+++ b/thirdparty/zstd/common/huf.h
@@ -1,7 +1,7 @@
/* ******************************************************************
* huff0 huffman codec,
* part of Finite State Entropy library
- * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
*
* You can contact the author at :
* - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
@@ -192,6 +192,7 @@ size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize,
unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue);
size_t HUF_buildCTable (HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue, unsigned maxNbBits); /* @return : maxNbBits; CTable and count can overlap. In which case, CTable will overwrite count content */
size_t HUF_writeCTable (void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog);
+size_t HUF_writeCTable_wksp(void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog, void* workspace, size_t workspaceSize);
size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable);
size_t HUF_estimateCompressedSize(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue);
int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue);
@@ -278,7 +279,7 @@ U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize);
* a required workspace size greater than that specified in the following
* macro.
*/
-#define HUF_DECOMPRESS_WORKSPACE_SIZE (2 << 10)
+#define HUF_DECOMPRESS_WORKSPACE_SIZE ((2 << 10) + (1 << 9))
#define HUF_DECOMPRESS_WORKSPACE_SIZE_U32 (HUF_DECOMPRESS_WORKSPACE_SIZE / sizeof(U32))
#ifndef HUF_FORCE_DECOMPRESS_X2
diff --git a/thirdparty/zstd/common/mem.h b/thirdparty/zstd/common/mem.h
index 4728ef767b..9f3b81ab9d 100644
--- a/thirdparty/zstd/common/mem.h
+++ b/thirdparty/zstd/common/mem.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
@@ -143,9 +143,7 @@ MEM_STATIC size_t MEM_swapST(size_t in);
* Prefer these methods in priority order (0 > 1 > 2)
*/
#ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */
-# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) )
-# define MEM_FORCE_MEMORY_ACCESS 2
-# elif defined(__INTEL_COMPILER) || defined(__GNUC__) || defined(__ICCARM__)
+# if defined(__INTEL_COMPILER) || defined(__GNUC__) || defined(__ICCARM__)
# define MEM_FORCE_MEMORY_ACCESS 1
# endif
#endif
@@ -308,7 +306,7 @@ MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val)
MEM_STATIC U32 MEM_readLE24(const void* memPtr)
{
- return MEM_readLE16(memPtr) + (((const BYTE*)memPtr)[2] << 16);
+ return (U32)MEM_readLE16(memPtr) + ((U32)(((const BYTE*)memPtr)[2]) << 16);
}
MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val)
diff --git a/thirdparty/zstd/common/pool.c b/thirdparty/zstd/common/pool.c
index 4c1b83376f..ea70b8b65a 100644
--- a/thirdparty/zstd/common/pool.c
+++ b/thirdparty/zstd/common/pool.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
diff --git a/thirdparty/zstd/common/pool.h b/thirdparty/zstd/common/pool.h
index 63954ca6ca..e18aa0708f 100644
--- a/thirdparty/zstd/common/pool.h
+++ b/thirdparty/zstd/common/pool.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
diff --git a/thirdparty/zstd/common/xxhash.c b/thirdparty/zstd/common/xxhash.c
index e708df3c33..926b33604e 100644
--- a/thirdparty/zstd/common/xxhash.c
+++ b/thirdparty/zstd/common/xxhash.c
@@ -1,6 +1,6 @@
/*
* xxHash - Fast Hash algorithm
- * Copyright (c) 2012-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
*
* You can contact the author at :
* - xxHash homepage: http://www.xxhash.com
@@ -30,9 +30,7 @@
* Prefer these methods in priority order (0 > 1 > 2)
*/
#ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */
-# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) )
-# define XXH_FORCE_MEMORY_ACCESS 2
-# elif (defined(__INTEL_COMPILER) && !defined(WIN32)) || \
+# if (defined(__INTEL_COMPILER) && !defined(WIN32)) || \
(defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) )) || \
defined(__ICCARM__)
# define XXH_FORCE_MEMORY_ACCESS 1
diff --git a/thirdparty/zstd/common/xxhash.h b/thirdparty/zstd/common/xxhash.h
index eceb55d5e0..16c1f1617b 100644
--- a/thirdparty/zstd/common/xxhash.h
+++ b/thirdparty/zstd/common/xxhash.h
@@ -1,7 +1,7 @@
/*
* xxHash - Extremely Fast Hash algorithm
* Header File
- * Copyright (c) 2012-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
*
* You can contact the author at :
* - xxHash source repository : https://github.com/Cyan4973/xxHash
diff --git a/thirdparty/zstd/common/zstd_common.c b/thirdparty/zstd/common/zstd_common.c
index 939e9f08fa..3d7e35b309 100644
--- a/thirdparty/zstd/common/zstd_common.c
+++ b/thirdparty/zstd/common/zstd_common.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
diff --git a/thirdparty/zstd/common/zstd_deps.h b/thirdparty/zstd/common/zstd_deps.h
index 0fb8b7818b..14211344a0 100644
--- a/thirdparty/zstd/common/zstd_deps.h
+++ b/thirdparty/zstd/common/zstd_deps.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Facebook, Inc.
+ * Copyright (c) Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
diff --git a/thirdparty/zstd/common/zstd_internal.h b/thirdparty/zstd/common/zstd_internal.h
index 0991f20a08..68252e987e 100644
--- a/thirdparty/zstd/common/zstd_internal.h
+++ b/thirdparty/zstd/common/zstd_internal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
@@ -36,6 +36,11 @@
# define XXH_STATIC_LINKING_ONLY /* XXH64_state_t */
#endif
#include "xxhash.h" /* XXH_reset, update, digest */
+#ifndef ZSTD_NO_TRACE
+# include "zstd_trace.h"
+#else
+# define ZSTD_TRACE 0
+#endif
#if defined (__cplusplus)
extern "C" {
@@ -347,11 +352,18 @@ typedef enum {
* Private declarations
*********************************************/
typedef struct seqDef_s {
- U32 offset; /* Offset code of the sequence */
+ U32 offset; /* offset == rawOffset + ZSTD_REP_NUM, or equivalently, offCode + 1 */
U16 litLength;
U16 matchLength;
} seqDef;
+/* Controls whether seqStore has a single "long" litLength or matchLength. See seqStore_t. */
+typedef enum {
+ ZSTD_llt_none = 0, /* no longLengthType */
+ ZSTD_llt_literalLength = 1, /* represents a long literal */
+ ZSTD_llt_matchLength = 2 /* represents a long match */
+} ZSTD_longLengthType_e;
+
typedef struct {
seqDef* sequencesStart;
seqDef* sequences; /* ptr to end of sequences */
@@ -363,12 +375,12 @@ typedef struct {
size_t maxNbSeq;
size_t maxNbLit;
- /* longLengthPos and longLengthID to allow us to represent either a single litLength or matchLength
+ /* longLengthPos and longLengthType to allow us to represent either a single litLength or matchLength
* in the seqStore that has a value larger than U16 (if it exists). To do so, we increment
- * the existing value of the litLength or matchLength by 0x10000.
+ * the existing value of the litLength or matchLength by 0x10000.
*/
- U32 longLengthID; /* 0 == no longLength; 1 == Represent the long literal; 2 == Represent the long match; */
- U32 longLengthPos; /* Index of the sequence to apply long length modification to */
+ ZSTD_longLengthType_e longLengthType;
+ U32 longLengthPos; /* Index of the sequence to apply long length modification to */
} seqStore_t;
typedef struct {
@@ -378,7 +390,7 @@ typedef struct {
/**
* Returns the ZSTD_sequenceLength for the given sequences. It handles the decoding of long sequences
- * indicated by longLengthPos and longLengthID, and adds MINMATCH back to matchLength.
+ * indicated by longLengthPos and longLengthType, and adds MINMATCH back to matchLength.
*/
MEM_STATIC ZSTD_sequenceLength ZSTD_getSequenceLength(seqStore_t const* seqStore, seqDef const* seq)
{
@@ -386,10 +398,10 @@ MEM_STATIC ZSTD_sequenceLength ZSTD_getSequenceLength(seqStore_t const* seqStore
seqLen.litLength = seq->litLength;
seqLen.matchLength = seq->matchLength + MINMATCH;
if (seqStore->longLengthPos == (U32)(seq - seqStore->sequencesStart)) {
- if (seqStore->longLengthID == 1) {
+ if (seqStore->longLengthType == ZSTD_llt_literalLength) {
seqLen.litLength += 0xFFFF;
}
- if (seqStore->longLengthID == 2) {
+ if (seqStore->longLengthType == ZSTD_llt_matchLength) {
seqLen.matchLength += 0xFFFF;
}
}
diff --git a/thirdparty/zstd/common/zstd_trace.h b/thirdparty/zstd/common/zstd_trace.h
new file mode 100644
index 0000000000..2da5640771
--- /dev/null
+++ b/thirdparty/zstd/common/zstd_trace.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef ZSTD_TRACE_H
+#define ZSTD_TRACE_H
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#include <stddef.h>
+
+/* weak symbol support */
+#if !defined(ZSTD_HAVE_WEAK_SYMBOLS) && defined(__GNUC__) && \
+ !defined(__APPLE__) && !defined(_WIN32) && !defined(__MINGW32__) && \
+ !defined(__CYGWIN__)
+# define ZSTD_HAVE_WEAK_SYMBOLS 1
+#else
+# define ZSTD_HAVE_WEAK_SYMBOLS 0
+#endif
+#if ZSTD_HAVE_WEAK_SYMBOLS
+# define ZSTD_WEAK_ATTR __attribute__((__weak__))
+#else
+# define ZSTD_WEAK_ATTR
+#endif
+
+/* Only enable tracing when weak symbols are available. */
+#ifndef ZSTD_TRACE
+# define ZSTD_TRACE ZSTD_HAVE_WEAK_SYMBOLS
+#endif
+
+#if ZSTD_TRACE
+
+struct ZSTD_CCtx_s;
+struct ZSTD_DCtx_s;
+struct ZSTD_CCtx_params_s;
+
+typedef struct {
+ /**
+ * ZSTD_VERSION_NUMBER
+ *
+ * This is guaranteed to be the first member of ZSTD_trace.
+ * Otherwise, this struct is not stable between versions. If
+ * the version number does not match your expectation, you
+ * should not interpret the rest of the struct.
+ */
+ unsigned version;
+ /**
+ * Non-zero if streaming (de)compression is used.
+ */
+ unsigned streaming;
+ /**
+ * The dictionary ID.
+ */
+ unsigned dictionaryID;
+ /**
+ * Is the dictionary cold?
+ * Only set on decompression.
+ */
+ unsigned dictionaryIsCold;
+ /**
+ * The dictionary size or zero if no dictionary.
+ */
+ size_t dictionarySize;
+ /**
+ * The uncompressed size of the data.
+ */
+ size_t uncompressedSize;
+ /**
+ * The compressed size of the data.
+ */
+ size_t compressedSize;
+ /**
+ * The fully resolved CCtx parameters (NULL on decompression).
+ */
+ struct ZSTD_CCtx_params_s const* params;
+ /**
+ * The ZSTD_CCtx pointer (NULL on decompression).
+ */
+ struct ZSTD_CCtx_s const* cctx;
+ /**
+ * The ZSTD_DCtx pointer (NULL on compression).
+ */
+ struct ZSTD_DCtx_s const* dctx;
+} ZSTD_Trace;
+
+/**
+ * A tracing context. It must be 0 when tracing is disabled.
+ * Otherwise, any non-zero value returned by a tracing begin()
+ * function is presented to any subsequent calls to end().
+ *
+ * Any non-zero value is treated as tracing is enabled and not
+ * interpreted by the library.
+ *
+ * Two possible uses are:
+ * * A timestamp for when the begin() function was called.
+ * * A unique key identifying the (de)compression, like the
+ * address of the [dc]ctx pointer if you need to track
+ * more information than just a timestamp.
+ */
+typedef unsigned long long ZSTD_TraceCtx;
+
+/**
+ * Trace the beginning of a compression call.
+ * @param cctx The dctx pointer for the compression.
+ * It can be used as a key to map begin() to end().
+ * @returns Non-zero if tracing is enabled. The return value is
+ * passed to ZSTD_trace_compress_end().
+ */
+ZSTD_WEAK_ATTR ZSTD_TraceCtx ZSTD_trace_compress_begin(
+ struct ZSTD_CCtx_s const* cctx);
+
+/**
+ * Trace the end of a compression call.
+ * @param ctx The return value of ZSTD_trace_compress_begin().
+ * @param trace The zstd tracing info.
+ */
+ZSTD_WEAK_ATTR void ZSTD_trace_compress_end(
+ ZSTD_TraceCtx ctx,
+ ZSTD_Trace const* trace);
+
+/**
+ * Trace the beginning of a decompression call.
+ * @param dctx The dctx pointer for the decompression.
+ * It can be used as a key to map begin() to end().
+ * @returns Non-zero if tracing is enabled. The return value is
+ * passed to ZSTD_trace_compress_end().
+ */
+ZSTD_WEAK_ATTR ZSTD_TraceCtx ZSTD_trace_decompress_begin(
+ struct ZSTD_DCtx_s const* dctx);
+
+/**
+ * Trace the end of a decompression call.
+ * @param ctx The return value of ZSTD_trace_decompress_begin().
+ * @param trace The zstd tracing info.
+ */
+ZSTD_WEAK_ATTR void ZSTD_trace_decompress_end(
+ ZSTD_TraceCtx ctx,
+ ZSTD_Trace const* trace);
+
+#endif /* ZSTD_TRACE */
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* ZSTD_TRACE_H */
diff --git a/thirdparty/zstd/compress/fse_compress.c b/thirdparty/zstd/compress/fse_compress.c
index 304a82b3cc..b4297ec88a 100644
--- a/thirdparty/zstd/compress/fse_compress.c
+++ b/thirdparty/zstd/compress/fse_compress.c
@@ -1,6 +1,6 @@
/* ******************************************************************
* FSE : Finite State Entropy encoder
- * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
*
* You can contact the author at :
* - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
diff --git a/thirdparty/zstd/compress/hist.c b/thirdparty/zstd/compress/hist.c
index a9659d11ad..073c57e752 100644
--- a/thirdparty/zstd/compress/hist.c
+++ b/thirdparty/zstd/compress/hist.c
@@ -1,7 +1,7 @@
/* ******************************************************************
* hist : Histogram functions
* part of Finite State Entropy project
- * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
*
* You can contact the author at :
* - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
diff --git a/thirdparty/zstd/compress/hist.h b/thirdparty/zstd/compress/hist.h
index fb9ead6834..228ed48a71 100644
--- a/thirdparty/zstd/compress/hist.h
+++ b/thirdparty/zstd/compress/hist.h
@@ -1,7 +1,7 @@
/* ******************************************************************
* hist : Histogram functions
* part of Finite State Entropy project
- * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
*
* You can contact the author at :
* - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
diff --git a/thirdparty/zstd/compress/huf_compress.c b/thirdparty/zstd/compress/huf_compress.c
index 302e08864d..485906e678 100644
--- a/thirdparty/zstd/compress/huf_compress.c
+++ b/thirdparty/zstd/compress/huf_compress.c
@@ -1,6 +1,6 @@
/* ******************************************************************
* Huffman encoder, part of New Generation Entropy library
- * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
*
* You can contact the author at :
* - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
@@ -59,7 +59,15 @@ unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxS
* Note : all elements within weightTable are supposed to be <= HUF_TABLELOG_MAX.
*/
#define MAX_FSE_TABLELOG_FOR_HUFF_HEADER 6
-static size_t HUF_compressWeights (void* dst, size_t dstSize, const void* weightTable, size_t wtSize)
+
+typedef struct {
+ FSE_CTable CTable[FSE_CTABLE_SIZE_U32(MAX_FSE_TABLELOG_FOR_HUFF_HEADER, HUF_TABLELOG_MAX)];
+ U32 scratchBuffer[FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(HUF_TABLELOG_MAX, MAX_FSE_TABLELOG_FOR_HUFF_HEADER)];
+ unsigned count[HUF_TABLELOG_MAX+1];
+ S16 norm[HUF_TABLELOG_MAX+1];
+} HUF_CompressWeightsWksp;
+
+static size_t HUF_compressWeights(void* dst, size_t dstSize, const void* weightTable, size_t wtSize, void* workspace, size_t workspaceSize)
{
BYTE* const ostart = (BYTE*) dst;
BYTE* op = ostart;
@@ -67,33 +75,30 @@ static size_t HUF_compressWeights (void* dst, size_t dstSize, const void* weight
unsigned maxSymbolValue = HUF_TABLELOG_MAX;
U32 tableLog = MAX_FSE_TABLELOG_FOR_HUFF_HEADER;
+ HUF_CompressWeightsWksp* wksp = (HUF_CompressWeightsWksp*)workspace;
- FSE_CTable CTable[FSE_CTABLE_SIZE_U32(MAX_FSE_TABLELOG_FOR_HUFF_HEADER, HUF_TABLELOG_MAX)];
- U32 scratchBuffer[FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(HUF_TABLELOG_MAX, MAX_FSE_TABLELOG_FOR_HUFF_HEADER)];
-
- unsigned count[HUF_TABLELOG_MAX+1];
- S16 norm[HUF_TABLELOG_MAX+1];
+ if (workspaceSize < sizeof(HUF_CompressWeightsWksp)) return ERROR(GENERIC);
/* init conditions */
if (wtSize <= 1) return 0; /* Not compressible */
/* Scan input and build symbol stats */
- { unsigned const maxCount = HIST_count_simple(count, &maxSymbolValue, weightTable, wtSize); /* never fails */
+ { unsigned const maxCount = HIST_count_simple(wksp->count, &maxSymbolValue, weightTable, wtSize); /* never fails */
if (maxCount == wtSize) return 1; /* only a single symbol in src : rle */
if (maxCount == 1) return 0; /* each symbol present maximum once => not compressible */
}
tableLog = FSE_optimalTableLog(tableLog, wtSize, maxSymbolValue);
- CHECK_F( FSE_normalizeCount(norm, tableLog, count, wtSize, maxSymbolValue, /* useLowProbCount */ 0) );
+ CHECK_F( FSE_normalizeCount(wksp->norm, tableLog, wksp->count, wtSize, maxSymbolValue, /* useLowProbCount */ 0) );
/* Write table description header */
- { CHECK_V_F(hSize, FSE_writeNCount(op, (size_t)(oend-op), norm, maxSymbolValue, tableLog) );
+ { CHECK_V_F(hSize, FSE_writeNCount(op, (size_t)(oend-op), wksp->norm, maxSymbolValue, tableLog) );
op += hSize;
}
/* Compress */
- CHECK_F( FSE_buildCTable_wksp(CTable, norm, maxSymbolValue, tableLog, scratchBuffer, sizeof(scratchBuffer)) );
- { CHECK_V_F(cSize, FSE_compress_usingCTable(op, (size_t)(oend - op), weightTable, wtSize, CTable) );
+ CHECK_F( FSE_buildCTable_wksp(wksp->CTable, wksp->norm, maxSymbolValue, tableLog, wksp->scratchBuffer, sizeof(wksp->scratchBuffer)) );
+ { CHECK_V_F(cSize, FSE_compress_usingCTable(op, (size_t)(oend - op), weightTable, wtSize, wksp->CTable) );
if (cSize == 0) return 0; /* not enough space for compressed data */
op += cSize;
}
@@ -102,29 +107,33 @@ static size_t HUF_compressWeights (void* dst, size_t dstSize, const void* weight
}
-/*! HUF_writeCTable() :
- `CTable` : Huffman tree to save, using huf representation.
- @return : size of saved CTable */
-size_t HUF_writeCTable (void* dst, size_t maxDstSize,
- const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog)
-{
+typedef struct {
+ HUF_CompressWeightsWksp wksp;
BYTE bitsToWeight[HUF_TABLELOG_MAX + 1]; /* precomputed conversion table */
BYTE huffWeight[HUF_SYMBOLVALUE_MAX];
+} HUF_WriteCTableWksp;
+
+size_t HUF_writeCTable_wksp(void* dst, size_t maxDstSize,
+ const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog,
+ void* workspace, size_t workspaceSize)
+{
BYTE* op = (BYTE*)dst;
U32 n;
+ HUF_WriteCTableWksp* wksp = (HUF_WriteCTableWksp*)workspace;
- /* check conditions */
+ /* check conditions */
+ if (workspaceSize < sizeof(HUF_WriteCTableWksp)) return ERROR(GENERIC);
if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(maxSymbolValue_tooLarge);
/* convert to weight */
- bitsToWeight[0] = 0;
+ wksp->bitsToWeight[0] = 0;
for (n=1; n<huffLog+1; n++)
- bitsToWeight[n] = (BYTE)(huffLog + 1 - n);
+ wksp->bitsToWeight[n] = (BYTE)(huffLog + 1 - n);
for (n=0; n<maxSymbolValue; n++)
- huffWeight[n] = bitsToWeight[CTable[n].nbBits];
+ wksp->huffWeight[n] = wksp->bitsToWeight[CTable[n].nbBits];
/* attempt weights compression by FSE */
- { CHECK_V_F(hSize, HUF_compressWeights(op+1, maxDstSize-1, huffWeight, maxSymbolValue) );
+ { CHECK_V_F(hSize, HUF_compressWeights(op+1, maxDstSize-1, wksp->huffWeight, maxSymbolValue, &wksp->wksp, sizeof(wksp->wksp)) );
if ((hSize>1) & (hSize < maxSymbolValue/2)) { /* FSE compressed */
op[0] = (BYTE)hSize;
return hSize+1;
@@ -134,12 +143,22 @@ size_t HUF_writeCTable (void* dst, size_t maxDstSize,
if (maxSymbolValue > (256-128)) return ERROR(GENERIC); /* should not happen : likely means source cannot be compressed */
if (((maxSymbolValue+1)/2) + 1 > maxDstSize) return ERROR(dstSize_tooSmall); /* not enough space within dst buffer */
op[0] = (BYTE)(128 /*special case*/ + (maxSymbolValue-1));
- huffWeight[maxSymbolValue] = 0; /* to be sure it doesn't cause msan issue in final combination */
+ wksp->huffWeight[maxSymbolValue] = 0; /* to be sure it doesn't cause msan issue in final combination */
for (n=0; n<maxSymbolValue; n+=2)
- op[(n/2)+1] = (BYTE)((huffWeight[n] << 4) + huffWeight[n+1]);
+ op[(n/2)+1] = (BYTE)((wksp->huffWeight[n] << 4) + wksp->huffWeight[n+1]);
return ((maxSymbolValue+1)/2) + 1;
}
+/*! HUF_writeCTable() :
+ `CTable` : Huffman tree to save, using huf representation.
+ @return : size of saved CTable */
+size_t HUF_writeCTable (void* dst, size_t maxDstSize,
+ const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog)
+{
+ HUF_WriteCTableWksp wksp;
+ return HUF_writeCTable_wksp(dst, maxDstSize, CTable, maxSymbolValue, huffLog, &wksp, sizeof(wksp));
+}
+
size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize, unsigned* hasZeroWeights)
{
@@ -732,7 +751,10 @@ static size_t HUF_compressCTable_internal(
typedef struct {
unsigned count[HUF_SYMBOLVALUE_MAX + 1];
HUF_CElt CTable[HUF_SYMBOLVALUE_MAX + 1];
- HUF_buildCTable_wksp_tables buildCTable_wksp;
+ union {
+ HUF_buildCTable_wksp_tables buildCTable_wksp;
+ HUF_WriteCTableWksp writeCTable_wksp;
+ } wksps;
} HUF_compress_tables_t;
/* HUF_compress_internal() :
@@ -795,7 +817,7 @@ HUF_compress_internal (void* dst, size_t dstSize,
huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue);
{ size_t const maxBits = HUF_buildCTable_wksp(table->CTable, table->count,
maxSymbolValue, huffLog,
- &table->buildCTable_wksp, sizeof(table->buildCTable_wksp));
+ &table->wksps.buildCTable_wksp, sizeof(table->wksps.buildCTable_wksp));
CHECK_F(maxBits);
huffLog = (U32)maxBits;
/* Zero unused symbols in CTable, so we can check it for validity */
@@ -804,7 +826,8 @@ HUF_compress_internal (void* dst, size_t dstSize,
}
/* Write table description header */
- { CHECK_V_F(hSize, HUF_writeCTable (op, dstSize, table->CTable, maxSymbolValue, huffLog) );
+ { CHECK_V_F(hSize, HUF_writeCTable_wksp(op, dstSize, table->CTable, maxSymbolValue, huffLog,
+ &table->wksps.writeCTable_wksp, sizeof(table->wksps.writeCTable_wksp)) );
/* Check if using previous huffman table is beneficial */
if (repeat && *repeat != HUF_repeat_none) {
size_t const oldSize = HUF_estimateCompressedSize(oldHufTable, table->count, maxSymbolValue);
diff --git a/thirdparty/zstd/compress/zstd_compress.c b/thirdparty/zstd/compress/zstd_compress.c
index 386b051df6..b7ee2980a7 100644
--- a/thirdparty/zstd/compress/zstd_compress.c
+++ b/thirdparty/zstd/compress/zstd_compress.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
@@ -72,6 +72,10 @@ struct ZSTD_CDict_s {
ZSTD_customMem customMem;
U32 dictID;
int compressionLevel; /* 0 indicates that advanced API was used to select CDict params */
+ ZSTD_useRowMatchFinderMode_e useRowMatchFinder; /* Indicates whether the CDict was created with params that would use
+ * row-based matchfinder. Unless the cdict is reloaded, we will use
+ * the same greedy/lazy matchfinder at compression time.
+ */
}; /* typedef'd to ZSTD_CDict within "zstd.h" */
ZSTD_CCtx* ZSTD_createCCtx(void)
@@ -202,6 +206,49 @@ size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
/* private API call, for dictBuilder only */
const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); }
+/* Returns true if the strategy supports using a row based matchfinder */
+static int ZSTD_rowMatchFinderSupported(const ZSTD_strategy strategy) {
+ return (strategy >= ZSTD_greedy && strategy <= ZSTD_lazy2);
+}
+
+/* Returns true if the strategy and useRowMatchFinder mode indicate that we will use the row based matchfinder
+ * for this compression.
+ */
+static int ZSTD_rowMatchFinderUsed(const ZSTD_strategy strategy, const ZSTD_useRowMatchFinderMode_e mode) {
+ assert(mode != ZSTD_urm_auto);
+ return ZSTD_rowMatchFinderSupported(strategy) && (mode == ZSTD_urm_enableRowMatchFinder);
+}
+
+/* Returns row matchfinder usage enum given an initial mode and cParams */
+static ZSTD_useRowMatchFinderMode_e ZSTD_resolveRowMatchFinderMode(ZSTD_useRowMatchFinderMode_e mode,
+ const ZSTD_compressionParameters* const cParams) {
+#if !defined(ZSTD_NO_INTRINSICS) && (defined(__SSE2__) || defined(__ARM_NEON))
+ int const kHasSIMD128 = 1;
+#else
+ int const kHasSIMD128 = 0;
+#endif
+ if (mode != ZSTD_urm_auto) return mode; /* if requested enabled, but no SIMD, we still will use row matchfinder */
+ mode = ZSTD_urm_disableRowMatchFinder;
+ if (!ZSTD_rowMatchFinderSupported(cParams->strategy)) return mode;
+ if (kHasSIMD128) {
+ if (cParams->windowLog > 14) mode = ZSTD_urm_enableRowMatchFinder;
+ } else {
+ if (cParams->windowLog > 17) mode = ZSTD_urm_enableRowMatchFinder;
+ }
+ return mode;
+}
+
+/* Returns 1 if the arguments indicate that we should allocate a chainTable, 0 otherwise */
+static int ZSTD_allocateChainTable(const ZSTD_strategy strategy,
+ const ZSTD_useRowMatchFinderMode_e useRowMatchFinder,
+ const U32 forDDSDict) {
+ assert(useRowMatchFinder != ZSTD_urm_auto);
+ /* We always should allocate a chaintable if we are allocating a matchstate for a DDS dictionary matchstate.
+ * We do not allocate a chaintable if we are using ZSTD_fast, or are using the row-based matchfinder.
+ */
+ return forDDSDict || ((strategy != ZSTD_fast) && !ZSTD_rowMatchFinderUsed(strategy, useRowMatchFinder));
+}
+
/* Returns 1 if compression parameters are such that we should
* enable long distance matching (wlog >= 27, strategy >= btopt).
* Returns 0 otherwise.
@@ -210,6 +257,14 @@ static U32 ZSTD_CParams_shouldEnableLdm(const ZSTD_compressionParameters* const
return cParams->strategy >= ZSTD_btopt && cParams->windowLog >= 27;
}
+/* Returns 1 if compression parameters are such that we should
+ * enable blockSplitter (wlog >= 17, strategy >= btopt).
+ * Returns 0 otherwise.
+ */
+static U32 ZSTD_CParams_useBlockSplitter(const ZSTD_compressionParameters* const cParams) {
+ return cParams->strategy >= ZSTD_btopt && cParams->windowLog >= 17;
+}
+
static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams(
ZSTD_compressionParameters cParams)
{
@@ -218,6 +273,7 @@ static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams(
ZSTD_CCtxParams_init(&cctxParams, ZSTD_CLEVEL_DEFAULT);
cctxParams.cParams = cParams;
+ /* Adjust advanced params according to cParams */
if (ZSTD_CParams_shouldEnableLdm(&cParams)) {
DEBUGLOG(4, "ZSTD_makeCCtxParamsFromCParams(): Including LDM into cctx params");
cctxParams.ldmParams.enableLdm = 1;
@@ -227,6 +283,12 @@ static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams(
assert(cctxParams.ldmParams.hashRateLog < 32);
}
+ if (ZSTD_CParams_useBlockSplitter(&cParams)) {
+ DEBUGLOG(4, "ZSTD_makeCCtxParamsFromCParams(): Including block splitting into cctx params");
+ cctxParams.splitBlocks = 1;
+ }
+
+ cctxParams.useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(cctxParams.useRowMatchFinder, &cParams);
assert(!ZSTD_checkCParams(cParams));
return cctxParams;
}
@@ -269,29 +331,48 @@ size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel)
return 0;
}
+#define ZSTD_NO_CLEVEL 0
+
+/**
+ * Initializes the cctxParams from params and compressionLevel.
+ * @param compressionLevel If params are derived from a compression level then that compression level, otherwise ZSTD_NO_CLEVEL.
+ */
+static void ZSTD_CCtxParams_init_internal(ZSTD_CCtx_params* cctxParams, ZSTD_parameters const* params, int compressionLevel)
+{
+ assert(!ZSTD_checkCParams(params->cParams));
+ ZSTD_memset(cctxParams, 0, sizeof(*cctxParams));
+ cctxParams->cParams = params->cParams;
+ cctxParams->fParams = params->fParams;
+ /* Should not matter, as all cParams are presumed properly defined.
+ * But, set it for tracing anyway.
+ */
+ cctxParams->compressionLevel = compressionLevel;
+ cctxParams->useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(cctxParams->useRowMatchFinder, &params->cParams);
+ DEBUGLOG(4, "ZSTD_CCtxParams_init_internal: useRowMatchFinder=%d", cctxParams->useRowMatchFinder);
+}
+
size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params)
{
RETURN_ERROR_IF(!cctxParams, GENERIC, "NULL pointer!");
FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) , "");
- ZSTD_memset(cctxParams, 0, sizeof(*cctxParams));
- assert(!ZSTD_checkCParams(params.cParams));
- cctxParams->cParams = params.cParams;
- cctxParams->fParams = params.fParams;
- cctxParams->compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */
+ ZSTD_CCtxParams_init_internal(cctxParams, &params, ZSTD_NO_CLEVEL);
return 0;
}
-/* ZSTD_assignParamsToCCtxParams() :
- * params is presumed valid at this stage */
-static ZSTD_CCtx_params ZSTD_assignParamsToCCtxParams(
- const ZSTD_CCtx_params* cctxParams, const ZSTD_parameters* params)
+/**
+ * Sets cctxParams' cParams and fParams from params, but otherwise leaves them alone.
+ * @param param Validated zstd parameters.
+ */
+static void ZSTD_CCtxParams_setZstdParams(
+ ZSTD_CCtx_params* cctxParams, const ZSTD_parameters* params)
{
- ZSTD_CCtx_params ret = *cctxParams;
assert(!ZSTD_checkCParams(params->cParams));
- ret.cParams = params->cParams;
- ret.fParams = params->fParams;
- ret.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */
- return ret;
+ cctxParams->cParams = params->cParams;
+ cctxParams->fParams = params->fParams;
+ /* Should not matter, as all cParams are presumed properly defined.
+ * But, set it for tracing anyway.
+ */
+ cctxParams->compressionLevel = ZSTD_NO_CLEVEL;
}
ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param)
@@ -468,6 +549,21 @@ ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param)
bounds.upperBound = 1;
return bounds;
+ case ZSTD_c_splitBlocks:
+ bounds.lowerBound = 0;
+ bounds.upperBound = 1;
+ return bounds;
+
+ case ZSTD_c_useRowMatchFinder:
+ bounds.lowerBound = (int)ZSTD_urm_auto;
+ bounds.upperBound = (int)ZSTD_urm_enableRowMatchFinder;
+ return bounds;
+
+ case ZSTD_c_deterministicRefPrefix:
+ bounds.lowerBound = 0;
+ bounds.upperBound = 1;
+ return bounds;
+
default:
bounds.error = ERROR(parameter_unsupported);
return bounds;
@@ -529,6 +625,9 @@ static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param)
case ZSTD_c_stableOutBuffer:
case ZSTD_c_blockDelimiters:
case ZSTD_c_validateSequences:
+ case ZSTD_c_splitBlocks:
+ case ZSTD_c_useRowMatchFinder:
+ case ZSTD_c_deterministicRefPrefix:
default:
return 0;
}
@@ -581,6 +680,9 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value)
case ZSTD_c_stableOutBuffer:
case ZSTD_c_blockDelimiters:
case ZSTD_c_validateSequences:
+ case ZSTD_c_splitBlocks:
+ case ZSTD_c_useRowMatchFinder:
+ case ZSTD_c_deterministicRefPrefix:
break;
default: RETURN_ERROR(parameter_unsupported, "unknown parameter");
@@ -792,17 +894,32 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams,
CCtxParams->validateSequences = value;
return CCtxParams->validateSequences;
+ case ZSTD_c_splitBlocks:
+ BOUNDCHECK(ZSTD_c_splitBlocks, value);
+ CCtxParams->splitBlocks = value;
+ return CCtxParams->splitBlocks;
+
+ case ZSTD_c_useRowMatchFinder:
+ BOUNDCHECK(ZSTD_c_useRowMatchFinder, value);
+ CCtxParams->useRowMatchFinder = (ZSTD_useRowMatchFinderMode_e)value;
+ return CCtxParams->useRowMatchFinder;
+
+ case ZSTD_c_deterministicRefPrefix:
+ BOUNDCHECK(ZSTD_c_deterministicRefPrefix, value);
+ CCtxParams->deterministicRefPrefix = !!value;
+ return CCtxParams->deterministicRefPrefix;
+
default: RETURN_ERROR(parameter_unsupported, "unknown parameter");
}
}
-size_t ZSTD_CCtx_getParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value)
+size_t ZSTD_CCtx_getParameter(ZSTD_CCtx const* cctx, ZSTD_cParameter param, int* value)
{
return ZSTD_CCtxParams_getParameter(&cctx->requestedParams, param, value);
}
size_t ZSTD_CCtxParams_getParameter(
- ZSTD_CCtx_params* CCtxParams, ZSTD_cParameter param, int* value)
+ ZSTD_CCtx_params const* CCtxParams, ZSTD_cParameter param, int* value)
{
switch(param)
{
@@ -915,6 +1032,15 @@ size_t ZSTD_CCtxParams_getParameter(
case ZSTD_c_validateSequences :
*value = (int)CCtxParams->validateSequences;
break;
+ case ZSTD_c_splitBlocks :
+ *value = (int)CCtxParams->splitBlocks;
+ break;
+ case ZSTD_c_useRowMatchFinder :
+ *value = (int)CCtxParams->useRowMatchFinder;
+ break;
+ case ZSTD_c_deterministicRefPrefix:
+ *value = (int)CCtxParams->deterministicRefPrefix;
+ break;
default: RETURN_ERROR(parameter_unsupported, "unknown parameter");
}
return 0;
@@ -1188,15 +1314,26 @@ ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar,
const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1);
assert(ZSTD_checkCParams(cPar)==0);
- if (dictSize && srcSize == ZSTD_CONTENTSIZE_UNKNOWN)
- srcSize = minSrcSize;
-
switch (mode) {
- case ZSTD_cpm_noAttachDict:
case ZSTD_cpm_unknown:
+ case ZSTD_cpm_noAttachDict:
+ /* If we don't know the source size, don't make any
+ * assumptions about it. We will already have selected
+ * smaller parameters if a dictionary is in use.
+ */
+ break;
case ZSTD_cpm_createCDict:
+ /* Assume a small source size when creating a dictionary
+ * with an unkown source size.
+ */
+ if (dictSize && srcSize == ZSTD_CONTENTSIZE_UNKNOWN)
+ srcSize = minSrcSize;
break;
case ZSTD_cpm_attachDict:
+ /* Dictionary has its own dedicated parameters which have
+ * already been selected. We are selecting parameters
+ * for only the source.
+ */
dictSize = 0;
break;
default:
@@ -1213,7 +1350,8 @@ ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar,
ZSTD_highbit32(tSize-1) + 1;
if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
}
- { U32 const dictAndWindowLog = ZSTD_dictAndWindowLog(cPar.windowLog, (U64)srcSize, (U64)dictSize);
+ if (srcSize != ZSTD_CONTENTSIZE_UNKNOWN) {
+ U32 const dictAndWindowLog = ZSTD_dictAndWindowLog(cPar.windowLog, (U64)srcSize, (U64)dictSize);
U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy);
if (cPar.hashLog > dictAndWindowLog+1) cPar.hashLog = dictAndWindowLog+1;
if (cycleLog > dictAndWindowLog)
@@ -1269,9 +1407,14 @@ ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams(
static size_t
ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams,
+ const ZSTD_useRowMatchFinderMode_e useRowMatchFinder,
+ const U32 enableDedicatedDictSearch,
const U32 forCCtx)
{
- size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog);
+ /* chain table size should be 0 for fast or row-hash strategies */
+ size_t const chainSize = ZSTD_allocateChainTable(cParams->strategy, useRowMatchFinder, enableDedicatedDictSearch && !forCCtx)
+ ? ((size_t)1 << cParams->chainLog)
+ : 0;
size_t const hSize = ((size_t)1) << cParams->hashLog;
U32 const hashLog3 = (forCCtx && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0;
size_t const h3Size = hashLog3 ? ((size_t)1) << hashLog3 : 0;
@@ -1281,24 +1424,34 @@ ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams,
+ hSize * sizeof(U32)
+ h3Size * sizeof(U32);
size_t const optPotentialSpace =
- ZSTD_cwksp_alloc_size((MaxML+1) * sizeof(U32))
- + ZSTD_cwksp_alloc_size((MaxLL+1) * sizeof(U32))
- + ZSTD_cwksp_alloc_size((MaxOff+1) * sizeof(U32))
- + ZSTD_cwksp_alloc_size((1<<Litbits) * sizeof(U32))
- + ZSTD_cwksp_alloc_size((ZSTD_OPT_NUM+1) * sizeof(ZSTD_match_t))
- + ZSTD_cwksp_alloc_size((ZSTD_OPT_NUM+1) * sizeof(ZSTD_optimal_t));
+ ZSTD_cwksp_aligned_alloc_size((MaxML+1) * sizeof(U32))
+ + ZSTD_cwksp_aligned_alloc_size((MaxLL+1) * sizeof(U32))
+ + ZSTD_cwksp_aligned_alloc_size((MaxOff+1) * sizeof(U32))
+ + ZSTD_cwksp_aligned_alloc_size((1<<Litbits) * sizeof(U32))
+ + ZSTD_cwksp_aligned_alloc_size((ZSTD_OPT_NUM+1) * sizeof(ZSTD_match_t))
+ + ZSTD_cwksp_aligned_alloc_size((ZSTD_OPT_NUM+1) * sizeof(ZSTD_optimal_t));
+ size_t const lazyAdditionalSpace = ZSTD_rowMatchFinderUsed(cParams->strategy, useRowMatchFinder)
+ ? ZSTD_cwksp_aligned_alloc_size(hSize*sizeof(U16))
+ : 0;
size_t const optSpace = (forCCtx && (cParams->strategy >= ZSTD_btopt))
? optPotentialSpace
: 0;
+ size_t const slackSpace = ZSTD_cwksp_slack_space_required();
+
+ /* tables are guaranteed to be sized in multiples of 64 bytes (or 16 uint32_t) */
+ ZSTD_STATIC_ASSERT(ZSTD_HASHLOG_MIN >= 4 && ZSTD_WINDOWLOG_MIN >= 4 && ZSTD_CHAINLOG_MIN >= 4);
+ assert(useRowMatchFinder != ZSTD_urm_auto);
+
DEBUGLOG(4, "chainSize: %u - hSize: %u - h3Size: %u",
(U32)chainSize, (U32)hSize, (U32)h3Size);
- return tableSpace + optSpace;
+ return tableSpace + optSpace + slackSpace + lazyAdditionalSpace;
}
static size_t ZSTD_estimateCCtxSize_usingCCtxParams_internal(
const ZSTD_compressionParameters* cParams,
const ldmParams_t* ldmParams,
const int isStatic,
+ const ZSTD_useRowMatchFinderMode_e useRowMatchFinder,
const size_t buffInSize,
const size_t buffOutSize,
const U64 pledgedSrcSize)
@@ -1308,16 +1461,16 @@ static size_t ZSTD_estimateCCtxSize_usingCCtxParams_internal(
U32 const divider = (cParams->minMatch==3) ? 3 : 4;
size_t const maxNbSeq = blockSize / divider;
size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize)
- + ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(seqDef))
+ + ZSTD_cwksp_aligned_alloc_size(maxNbSeq * sizeof(seqDef))
+ 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE));
size_t const entropySpace = ZSTD_cwksp_alloc_size(ENTROPY_WORKSPACE_SIZE);
size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t));
- size_t const matchStateSize = ZSTD_sizeof_matchState(cParams, /* forCCtx */ 1);
+ size_t const matchStateSize = ZSTD_sizeof_matchState(cParams, useRowMatchFinder, /* enableDedicatedDictSearch */ 0, /* forCCtx */ 1);
size_t const ldmSpace = ZSTD_ldm_getTableSize(*ldmParams);
size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(*ldmParams, blockSize);
size_t const ldmSeqSpace = ldmParams->enableLdm ?
- ZSTD_cwksp_alloc_size(maxNbLdmSeq * sizeof(rawSeq)) : 0;
+ ZSTD_cwksp_aligned_alloc_size(maxNbLdmSeq * sizeof(rawSeq)) : 0;
size_t const bufferSpace = ZSTD_cwksp_alloc_size(buffInSize)
@@ -1343,25 +1496,45 @@ size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params)
{
ZSTD_compressionParameters const cParams =
ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict);
+ ZSTD_useRowMatchFinderMode_e const useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(params->useRowMatchFinder,
+ &cParams);
RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only.");
/* estimateCCtxSize is for one-shot compression. So no buffers should
* be needed. However, we still allocate two 0-sized buffers, which can
* take space under ASAN. */
return ZSTD_estimateCCtxSize_usingCCtxParams_internal(
- &cParams, &params->ldmParams, 1, 0, 0, ZSTD_CONTENTSIZE_UNKNOWN);
+ &cParams, &params->ldmParams, 1, useRowMatchFinder, 0, 0, ZSTD_CONTENTSIZE_UNKNOWN);
}
size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams)
{
- ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams);
- return ZSTD_estimateCCtxSize_usingCCtxParams(&params);
+ ZSTD_CCtx_params initialParams = ZSTD_makeCCtxParamsFromCParams(cParams);
+ if (ZSTD_rowMatchFinderSupported(cParams.strategy)) {
+ /* Pick bigger of not using and using row-based matchfinder for greedy and lazy strategies */
+ size_t noRowCCtxSize;
+ size_t rowCCtxSize;
+ initialParams.useRowMatchFinder = ZSTD_urm_disableRowMatchFinder;
+ noRowCCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(&initialParams);
+ initialParams.useRowMatchFinder = ZSTD_urm_enableRowMatchFinder;
+ rowCCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(&initialParams);
+ return MAX(noRowCCtxSize, rowCCtxSize);
+ } else {
+ return ZSTD_estimateCCtxSize_usingCCtxParams(&initialParams);
+ }
}
static size_t ZSTD_estimateCCtxSize_internal(int compressionLevel)
{
- ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict);
- return ZSTD_estimateCCtxSize_usingCParams(cParams);
+ int tier = 0;
+ size_t largestSize = 0;
+ static const unsigned long long srcSizeTiers[4] = {16 KB, 128 KB, 256 KB, ZSTD_CONTENTSIZE_UNKNOWN};
+ for (; tier < 4; ++tier) {
+ /* Choose the set of cParams for a given level across all srcSizes that give the largest cctxSize */
+ ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, srcSizeTiers[tier], 0, ZSTD_cpm_noAttachDict);
+ largestSize = MAX(ZSTD_estimateCCtxSize_usingCParams(cParams), largestSize);
+ }
+ return largestSize;
}
size_t ZSTD_estimateCCtxSize(int compressionLevel)
@@ -1369,6 +1542,7 @@ size_t ZSTD_estimateCCtxSize(int compressionLevel)
int level;
size_t memBudget = 0;
for (level=MIN(compressionLevel, 1); level<=compressionLevel; level++) {
+ /* Ensure monotonically increasing memory usage as compression level increases */
size_t const newMB = ZSTD_estimateCCtxSize_internal(level);
if (newMB > memBudget) memBudget = newMB;
}
@@ -1387,17 +1561,29 @@ size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params)
size_t const outBuffSize = (params->outBufferMode == ZSTD_bm_buffered)
? ZSTD_compressBound(blockSize) + 1
: 0;
+ ZSTD_useRowMatchFinderMode_e const useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(params->useRowMatchFinder, &params->cParams);
return ZSTD_estimateCCtxSize_usingCCtxParams_internal(
- &cParams, &params->ldmParams, 1, inBuffSize, outBuffSize,
+ &cParams, &params->ldmParams, 1, useRowMatchFinder, inBuffSize, outBuffSize,
ZSTD_CONTENTSIZE_UNKNOWN);
}
}
size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams)
{
- ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams);
- return ZSTD_estimateCStreamSize_usingCCtxParams(&params);
+ ZSTD_CCtx_params initialParams = ZSTD_makeCCtxParamsFromCParams(cParams);
+ if (ZSTD_rowMatchFinderSupported(cParams.strategy)) {
+ /* Pick bigger of not using and using row-based matchfinder for greedy and lazy strategies */
+ size_t noRowCCtxSize;
+ size_t rowCCtxSize;
+ initialParams.useRowMatchFinder = ZSTD_urm_disableRowMatchFinder;
+ noRowCCtxSize = ZSTD_estimateCStreamSize_usingCCtxParams(&initialParams);
+ initialParams.useRowMatchFinder = ZSTD_urm_enableRowMatchFinder;
+ rowCCtxSize = ZSTD_estimateCStreamSize_usingCCtxParams(&initialParams);
+ return MAX(noRowCCtxSize, rowCCtxSize);
+ } else {
+ return ZSTD_estimateCStreamSize_usingCCtxParams(&initialParams);
+ }
}
static size_t ZSTD_estimateCStreamSize_internal(int compressionLevel)
@@ -1522,20 +1708,27 @@ typedef enum {
ZSTD_resetTarget_CCtx
} ZSTD_resetTarget_e;
+
static size_t
ZSTD_reset_matchState(ZSTD_matchState_t* ms,
ZSTD_cwksp* ws,
const ZSTD_compressionParameters* cParams,
+ const ZSTD_useRowMatchFinderMode_e useRowMatchFinder,
const ZSTD_compResetPolicy_e crp,
const ZSTD_indexResetPolicy_e forceResetIndex,
const ZSTD_resetTarget_e forWho)
{
- size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog);
+ /* disable chain table allocation for fast or row-based strategies */
+ size_t const chainSize = ZSTD_allocateChainTable(cParams->strategy, useRowMatchFinder,
+ ms->dedicatedDictSearch && (forWho == ZSTD_resetTarget_CDict))
+ ? ((size_t)1 << cParams->chainLog)
+ : 0;
size_t const hSize = ((size_t)1) << cParams->hashLog;
U32 const hashLog3 = ((forWho == ZSTD_resetTarget_CCtx) && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0;
size_t const h3Size = hashLog3 ? ((size_t)1) << hashLog3 : 0;
DEBUGLOG(4, "reset indices : %u", forceResetIndex == ZSTDirp_reset);
+ assert(useRowMatchFinder != ZSTD_urm_auto);
if (forceResetIndex == ZSTDirp_reset) {
ZSTD_window_init(&ms->window);
ZSTD_cwksp_mark_tables_dirty(ws);
@@ -1574,11 +1767,23 @@ ZSTD_reset_matchState(ZSTD_matchState_t* ms,
ms->opt.priceTable = (ZSTD_optimal_t*)ZSTD_cwksp_reserve_aligned(ws, (ZSTD_OPT_NUM+1) * sizeof(ZSTD_optimal_t));
}
+ if (ZSTD_rowMatchFinderUsed(cParams->strategy, useRowMatchFinder)) {
+ { /* Row match finder needs an additional table of hashes ("tags") */
+ size_t const tagTableSize = hSize*sizeof(U16);
+ ms->tagTable = (U16*)ZSTD_cwksp_reserve_aligned(ws, tagTableSize);
+ if (ms->tagTable) ZSTD_memset(ms->tagTable, 0, tagTableSize);
+ }
+ { /* Switch to 32-entry rows if searchLog is 5 (or more) */
+ U32 const rowLog = cParams->searchLog < 5 ? 4 : 5;
+ assert(cParams->hashLog > rowLog);
+ ms->rowHashLog = cParams->hashLog - rowLog;
+ }
+ }
+
ms->cParams = *cParams;
RETURN_ERROR_IF(ZSTD_cwksp_reserve_failed(ws), memory_allocation,
"failed a workspace allocation in ZSTD_reset_matchState");
-
return 0;
}
@@ -1595,62 +1800,85 @@ static int ZSTD_indexTooCloseToMax(ZSTD_window_t w)
return (size_t)(w.nextSrc - w.base) > (ZSTD_CURRENT_MAX - ZSTD_INDEXOVERFLOW_MARGIN);
}
+/** ZSTD_dictTooBig():
+ * When dictionaries are larger than ZSTD_CHUNKSIZE_MAX they can't be loaded in
+ * one go generically. So we ensure that in that case we reset the tables to zero,
+ * so that we can load as much of the dictionary as possible.
+ */
+static int ZSTD_dictTooBig(size_t const loadedDictSize)
+{
+ return loadedDictSize > ZSTD_CHUNKSIZE_MAX;
+}
+
/*! ZSTD_resetCCtx_internal() :
- note : `params` are assumed fully validated at this stage */
+ * @param loadedDictSize The size of the dictionary to be loaded
+ * into the context, if any. If no dictionary is used, or the
+ * dictionary is being attached / copied, then pass 0.
+ * note : `params` are assumed fully validated at this stage.
+ */
static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
- ZSTD_CCtx_params params,
+ ZSTD_CCtx_params const* params,
U64 const pledgedSrcSize,
+ size_t const loadedDictSize,
ZSTD_compResetPolicy_e const crp,
ZSTD_buffered_policy_e const zbuff)
{
ZSTD_cwksp* const ws = &zc->workspace;
- DEBUGLOG(4, "ZSTD_resetCCtx_internal: pledgedSrcSize=%u, wlog=%u",
- (U32)pledgedSrcSize, params.cParams.windowLog);
- assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
+ DEBUGLOG(4, "ZSTD_resetCCtx_internal: pledgedSrcSize=%u, wlog=%u, useRowMatchFinder=%d",
+ (U32)pledgedSrcSize, params->cParams.windowLog, (int)params->useRowMatchFinder);
+ assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams)));
zc->isFirstBlock = 1;
- if (params.ldmParams.enableLdm) {
+ /* Set applied params early so we can modify them for LDM,
+ * and point params at the applied params.
+ */
+ zc->appliedParams = *params;
+ params = &zc->appliedParams;
+
+ assert(params->useRowMatchFinder != ZSTD_urm_auto);
+ if (params->ldmParams.enableLdm) {
/* Adjust long distance matching parameters */
- ZSTD_ldm_adjustParameters(&params.ldmParams, &params.cParams);
- assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog);
- assert(params.ldmParams.hashRateLog < 32);
- zc->ldmState.hashPower = ZSTD_rollingHash_primePower(params.ldmParams.minMatchLength);
+ ZSTD_ldm_adjustParameters(&zc->appliedParams.ldmParams, &params->cParams);
+ assert(params->ldmParams.hashLog >= params->ldmParams.bucketSizeLog);
+ assert(params->ldmParams.hashRateLog < 32);
}
- { size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize));
+ { size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params->cParams.windowLog), pledgedSrcSize));
size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize);
- U32 const divider = (params.cParams.minMatch==3) ? 3 : 4;
+ U32 const divider = (params->cParams.minMatch==3) ? 3 : 4;
size_t const maxNbSeq = blockSize / divider;
- size_t const buffOutSize = (zbuff == ZSTDb_buffered && params.outBufferMode == ZSTD_bm_buffered)
+ size_t const buffOutSize = (zbuff == ZSTDb_buffered && params->outBufferMode == ZSTD_bm_buffered)
? ZSTD_compressBound(blockSize) + 1
: 0;
- size_t const buffInSize = (zbuff == ZSTDb_buffered && params.inBufferMode == ZSTD_bm_buffered)
+ size_t const buffInSize = (zbuff == ZSTDb_buffered && params->inBufferMode == ZSTD_bm_buffered)
? windowSize + blockSize
: 0;
- size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params.ldmParams, blockSize);
+ size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params->ldmParams, blockSize);
int const indexTooClose = ZSTD_indexTooCloseToMax(zc->blockState.matchState.window);
+ int const dictTooBig = ZSTD_dictTooBig(loadedDictSize);
ZSTD_indexResetPolicy_e needsIndexReset =
- (!indexTooClose && zc->initialized) ? ZSTDirp_continue : ZSTDirp_reset;
+ (indexTooClose || dictTooBig || !zc->initialized) ? ZSTDirp_reset : ZSTDirp_continue;
size_t const neededSpace =
ZSTD_estimateCCtxSize_usingCCtxParams_internal(
- &params.cParams, &params.ldmParams, zc->staticSize != 0,
+ &params->cParams, &params->ldmParams, zc->staticSize != 0, params->useRowMatchFinder,
buffInSize, buffOutSize, pledgedSrcSize);
+ int resizeWorkspace;
+
FORWARD_IF_ERROR(neededSpace, "cctx size estimate failed!");
if (!zc->staticSize) ZSTD_cwksp_bump_oversized_duration(ws, 0);
- /* Check if workspace is large enough, alloc a new one if needed */
- {
+ { /* Check if workspace is large enough, alloc a new one if needed */
int const workspaceTooSmall = ZSTD_cwksp_sizeof(ws) < neededSpace;
int const workspaceWasteful = ZSTD_cwksp_check_wasteful(ws, neededSpace);
-
+ resizeWorkspace = workspaceTooSmall || workspaceWasteful;
DEBUGLOG(4, "Need %zu B workspace", neededSpace);
DEBUGLOG(4, "windowSize: %zu - blockSize: %zu", windowSize, blockSize);
- if (workspaceTooSmall || workspaceWasteful) {
+ if (resizeWorkspace) {
DEBUGLOG(4, "Resize workspaceSize from %zuKB to %zuKB",
ZSTD_cwksp_sizeof(ws) >> 10,
neededSpace >> 10);
@@ -1678,8 +1906,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
ZSTD_cwksp_clear(ws);
/* init params */
- zc->appliedParams = params;
- zc->blockState.matchState.cParams = params.cParams;
+ zc->blockState.matchState.cParams = params->cParams;
zc->pledgedSrcSizePlusOne = pledgedSrcSize+1;
zc->consumedSrcSize = 0;
zc->producedCSize = 0;
@@ -1692,6 +1919,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
XXH64_reset(&zc->xxhState, 0);
zc->stage = ZSTDcs_init;
zc->dictID = 0;
+ zc->dictContentSize = 0;
ZSTD_reset_compressedBlockState(zc->blockState.prevCBlock);
@@ -1709,13 +1937,13 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
zc->outBuff = (char*)ZSTD_cwksp_reserve_buffer(ws, buffOutSize);
/* ldm bucketOffsets table */
- if (params.ldmParams.enableLdm) {
+ if (params->ldmParams.enableLdm) {
/* TODO: avoid memset? */
- size_t const ldmBucketSize =
- ((size_t)1) << (params.ldmParams.hashLog -
- params.ldmParams.bucketSizeLog);
- zc->ldmState.bucketOffsets = ZSTD_cwksp_reserve_buffer(ws, ldmBucketSize);
- ZSTD_memset(zc->ldmState.bucketOffsets, 0, ldmBucketSize);
+ size_t const numBuckets =
+ ((size_t)1) << (params->ldmParams.hashLog -
+ params->ldmParams.bucketSizeLog);
+ zc->ldmState.bucketOffsets = ZSTD_cwksp_reserve_buffer(ws, numBuckets);
+ ZSTD_memset(zc->ldmState.bucketOffsets, 0, numBuckets);
}
/* sequences storage */
@@ -1729,32 +1957,28 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
FORWARD_IF_ERROR(ZSTD_reset_matchState(
&zc->blockState.matchState,
ws,
- &params.cParams,
+ &params->cParams,
+ params->useRowMatchFinder,
crp,
needsIndexReset,
ZSTD_resetTarget_CCtx), "");
/* ldm hash table */
- if (params.ldmParams.enableLdm) {
+ if (params->ldmParams.enableLdm) {
/* TODO: avoid memset? */
- size_t const ldmHSize = ((size_t)1) << params.ldmParams.hashLog;
+ size_t const ldmHSize = ((size_t)1) << params->ldmParams.hashLog;
zc->ldmState.hashTable = (ldmEntry_t*)ZSTD_cwksp_reserve_aligned(ws, ldmHSize * sizeof(ldmEntry_t));
ZSTD_memset(zc->ldmState.hashTable, 0, ldmHSize * sizeof(ldmEntry_t));
zc->ldmSequences = (rawSeq*)ZSTD_cwksp_reserve_aligned(ws, maxNbLdmSeq * sizeof(rawSeq));
zc->maxNbLdmSequences = maxNbLdmSeq;
ZSTD_window_init(&zc->ldmState.window);
- ZSTD_window_clear(&zc->ldmState.window);
zc->ldmState.loadedDictEnd = 0;
}
- /* Due to alignment, when reusing a workspace, we can actually consume
- * up to 3 extra bytes for alignment. See the comments in zstd_cwksp.h
- */
- assert(ZSTD_cwksp_used(ws) >= neededSpace &&
- ZSTD_cwksp_used(ws) <= neededSpace + 3);
-
+ assert(ZSTD_cwksp_estimated_space_within_bounds(ws, neededSpace, resizeWorkspace));
DEBUGLOG(3, "wksp: finished allocating, %zd bytes remain available", ZSTD_cwksp_available_space(ws));
+
zc->initialized = 1;
return 0;
@@ -1810,6 +2034,8 @@ ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx* cctx,
U64 pledgedSrcSize,
ZSTD_buffered_policy_e zbuff)
{
+ DEBUGLOG(4, "ZSTD_resetCCtx_byAttachingCDict() pledgedSrcSize=%llu",
+ (unsigned long long)pledgedSrcSize);
{
ZSTD_compressionParameters adjusted_cdict_cParams = cdict->matchState.cParams;
unsigned const windowLog = params.cParams.windowLog;
@@ -1825,7 +2051,9 @@ ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx* cctx,
params.cParams = ZSTD_adjustCParams_internal(adjusted_cdict_cParams, pledgedSrcSize,
cdict->dictContentSize, ZSTD_cpm_attachDict);
params.cParams.windowLog = windowLog;
- FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
+ params.useRowMatchFinder = cdict->useRowMatchFinder; /* cdict overrides */
+ FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, &params, pledgedSrcSize,
+ /* loadedDictSize */ 0,
ZSTDcrp_makeClean, zbuff), "");
assert(cctx->appliedParams.cParams.strategy == adjusted_cdict_cParams.strategy);
}
@@ -1852,6 +2080,7 @@ ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx* cctx,
} }
cctx->dictID = cdict->dictID;
+ cctx->dictContentSize = cdict->dictContentSize;
/* copy block state */
ZSTD_memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState));
@@ -1868,15 +2097,17 @@ static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx,
const ZSTD_compressionParameters *cdict_cParams = &cdict->matchState.cParams;
assert(!cdict->matchState.dedicatedDictSearch);
-
- DEBUGLOG(4, "copying dictionary into context");
+ DEBUGLOG(4, "ZSTD_resetCCtx_byCopyingCDict() pledgedSrcSize=%llu",
+ (unsigned long long)pledgedSrcSize);
{ unsigned const windowLog = params.cParams.windowLog;
assert(windowLog != 0);
/* Copy only compression parameters related to tables. */
params.cParams = *cdict_cParams;
params.cParams.windowLog = windowLog;
- FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
+ params.useRowMatchFinder = cdict->useRowMatchFinder;
+ FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, &params, pledgedSrcSize,
+ /* loadedDictSize */ 0,
ZSTDcrp_leaveDirty, zbuff), "");
assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy);
assert(cctx->appliedParams.cParams.hashLog == cdict_cParams->hashLog);
@@ -1884,17 +2115,30 @@ static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx,
}
ZSTD_cwksp_mark_tables_dirty(&cctx->workspace);
+ assert(params.useRowMatchFinder != ZSTD_urm_auto);
/* copy tables */
- { size_t const chainSize = (cdict_cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cdict_cParams->chainLog);
+ { size_t const chainSize = ZSTD_allocateChainTable(cdict_cParams->strategy, cdict->useRowMatchFinder, 0 /* DDS guaranteed disabled */)
+ ? ((size_t)1 << cdict_cParams->chainLog)
+ : 0;
size_t const hSize = (size_t)1 << cdict_cParams->hashLog;
ZSTD_memcpy(cctx->blockState.matchState.hashTable,
cdict->matchState.hashTable,
hSize * sizeof(U32));
- ZSTD_memcpy(cctx->blockState.matchState.chainTable,
+ /* Do not copy cdict's chainTable if cctx has parameters such that it would not use chainTable */
+ if (ZSTD_allocateChainTable(cctx->appliedParams.cParams.strategy, cctx->appliedParams.useRowMatchFinder, 0 /* forDDSDict */)) {
+ ZSTD_memcpy(cctx->blockState.matchState.chainTable,
cdict->matchState.chainTable,
chainSize * sizeof(U32));
+ }
+ /* copy tag table */
+ if (ZSTD_rowMatchFinderUsed(cdict_cParams->strategy, cdict->useRowMatchFinder)) {
+ size_t const tagTableSize = hSize*sizeof(U16);
+ ZSTD_memcpy(cctx->blockState.matchState.tagTable,
+ cdict->matchState.tagTable,
+ tagTableSize);
+ }
}
/* Zero the hashTable3, since the cdict never fills it */
@@ -1915,6 +2159,7 @@ static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx,
}
cctx->dictID = cdict->dictID;
+ cctx->dictContentSize = cdict->dictContentSize;
/* copy block state */
ZSTD_memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState));
@@ -1957,16 +2202,18 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
U64 pledgedSrcSize,
ZSTD_buffered_policy_e zbuff)
{
- DEBUGLOG(5, "ZSTD_copyCCtx_internal");
RETURN_ERROR_IF(srcCCtx->stage!=ZSTDcs_init, stage_wrong,
"Can't copy a ctx that's not in init stage.");
-
+ DEBUGLOG(5, "ZSTD_copyCCtx_internal");
ZSTD_memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
{ ZSTD_CCtx_params params = dstCCtx->requestedParams;
/* Copy only compression parameters related to tables. */
params.cParams = srcCCtx->appliedParams.cParams;
+ assert(srcCCtx->appliedParams.useRowMatchFinder != ZSTD_urm_auto);
+ params.useRowMatchFinder = srcCCtx->appliedParams.useRowMatchFinder;
params.fParams = fParams;
- ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize,
+ ZSTD_resetCCtx_internal(dstCCtx, &params, pledgedSrcSize,
+ /* loadedDictSize */ 0,
ZSTDcrp_leaveDirty, zbuff);
assert(dstCCtx->appliedParams.cParams.windowLog == srcCCtx->appliedParams.cParams.windowLog);
assert(dstCCtx->appliedParams.cParams.strategy == srcCCtx->appliedParams.cParams.strategy);
@@ -1978,7 +2225,11 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
ZSTD_cwksp_mark_tables_dirty(&dstCCtx->workspace);
/* copy tables */
- { size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog);
+ { size_t const chainSize = ZSTD_allocateChainTable(srcCCtx->appliedParams.cParams.strategy,
+ srcCCtx->appliedParams.useRowMatchFinder,
+ 0 /* forDDSDict */)
+ ? ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog)
+ : 0;
size_t const hSize = (size_t)1 << srcCCtx->appliedParams.cParams.hashLog;
int const h3log = srcCCtx->blockState.matchState.hashLog3;
size_t const h3Size = h3log ? ((size_t)1 << h3log) : 0;
@@ -2005,6 +2256,7 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd;
}
dstCCtx->dictID = srcCCtx->dictID;
+ dstCCtx->dictContentSize = srcCCtx->dictContentSize;
/* copy block state */
ZSTD_memcpy(dstCCtx->blockState.prevCBlock, srcCCtx->blockState.prevCBlock, sizeof(*srcCCtx->blockState.prevCBlock));
@@ -2091,7 +2343,7 @@ static void ZSTD_reduceIndex (ZSTD_matchState_t* ms, ZSTD_CCtx_params const* par
ZSTD_reduceTable(ms->hashTable, hSize, reducerValue);
}
- if (params->cParams.strategy != ZSTD_fast) {
+ if (ZSTD_allocateChainTable(params->cParams.strategy, params->useRowMatchFinder, (U32)ms->dedicatedDictSearch)) {
U32 const chainSize = (U32)1 << params->cParams.chainLog;
if (params->cParams.strategy == ZSTD_btlazy2)
ZSTD_reduceTable_btlazy2(ms->chainTable, chainSize, reducerValue);
@@ -2128,9 +2380,9 @@ void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset);
mlCodeTable[u] = (BYTE)ZSTD_MLcode(mlv);
}
- if (seqStorePtr->longLengthID==1)
+ if (seqStorePtr->longLengthType==ZSTD_llt_literalLength)
llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
- if (seqStorePtr->longLengthID==2)
+ if (seqStorePtr->longLengthType==ZSTD_llt_matchLength)
mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
}
@@ -2144,10 +2396,158 @@ static int ZSTD_useTargetCBlockSize(const ZSTD_CCtx_params* cctxParams)
return (cctxParams->targetCBlockSize != 0);
}
-/* ZSTD_entropyCompressSequences_internal():
- * actually compresses both literals and sequences */
+/* ZSTD_blockSplitterEnabled():
+ * Returns if block splitting param is being used
+ * If used, compression will do best effort to split a block in order to improve compression ratio.
+ * Returns 1 if true, 0 otherwise. */
+static int ZSTD_blockSplitterEnabled(ZSTD_CCtx_params* cctxParams)
+{
+ DEBUGLOG(5, "ZSTD_blockSplitterEnabled(splitBlocks=%d)", cctxParams->splitBlocks);
+ return (cctxParams->splitBlocks != 0);
+}
+
+/* Type returned by ZSTD_buildSequencesStatistics containing finalized symbol encoding types
+ * and size of the sequences statistics
+ */
+typedef struct {
+ U32 LLtype;
+ U32 Offtype;
+ U32 MLtype;
+ size_t size;
+ size_t lastCountSize; /* Accounts for bug in 1.3.4. More detail in ZSTD_entropyCompressSeqStore_internal() */
+} ZSTD_symbolEncodingTypeStats_t;
+
+/* ZSTD_buildSequencesStatistics():
+ * Returns a ZSTD_symbolEncodingTypeStats_t, or a zstd error code in the `size` field.
+ * Modifies `nextEntropy` to have the appropriate values as a side effect.
+ * nbSeq must be greater than 0.
+ *
+ * entropyWkspSize must be of size at least ENTROPY_WORKSPACE_SIZE - (MaxSeq + 1)*sizeof(U32)
+ */
+static ZSTD_symbolEncodingTypeStats_t
+ZSTD_buildSequencesStatistics(seqStore_t* seqStorePtr, size_t nbSeq,
+ const ZSTD_fseCTables_t* prevEntropy, ZSTD_fseCTables_t* nextEntropy,
+ BYTE* dst, const BYTE* const dstEnd,
+ ZSTD_strategy strategy, unsigned* countWorkspace,
+ void* entropyWorkspace, size_t entropyWkspSize) {
+ BYTE* const ostart = dst;
+ const BYTE* const oend = dstEnd;
+ BYTE* op = ostart;
+ FSE_CTable* CTable_LitLength = nextEntropy->litlengthCTable;
+ FSE_CTable* CTable_OffsetBits = nextEntropy->offcodeCTable;
+ FSE_CTable* CTable_MatchLength = nextEntropy->matchlengthCTable;
+ const BYTE* const ofCodeTable = seqStorePtr->ofCode;
+ const BYTE* const llCodeTable = seqStorePtr->llCode;
+ const BYTE* const mlCodeTable = seqStorePtr->mlCode;
+ ZSTD_symbolEncodingTypeStats_t stats;
+
+ stats.lastCountSize = 0;
+ /* convert length/distances into codes */
+ ZSTD_seqToCodes(seqStorePtr);
+ assert(op <= oend);
+ assert(nbSeq != 0); /* ZSTD_selectEncodingType() divides by nbSeq */
+ /* build CTable for Literal Lengths */
+ { unsigned max = MaxLL;
+ size_t const mostFrequent = HIST_countFast_wksp(countWorkspace, &max, llCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */
+ DEBUGLOG(5, "Building LL table");
+ nextEntropy->litlength_repeatMode = prevEntropy->litlength_repeatMode;
+ stats.LLtype = ZSTD_selectEncodingType(&nextEntropy->litlength_repeatMode,
+ countWorkspace, max, mostFrequent, nbSeq,
+ LLFSELog, prevEntropy->litlengthCTable,
+ LL_defaultNorm, LL_defaultNormLog,
+ ZSTD_defaultAllowed, strategy);
+ assert(set_basic < set_compressed && set_rle < set_compressed);
+ assert(!(stats.LLtype < set_compressed && nextEntropy->litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
+ { size_t const countSize = ZSTD_buildCTable(
+ op, (size_t)(oend - op),
+ CTable_LitLength, LLFSELog, (symbolEncodingType_e)stats.LLtype,
+ countWorkspace, max, llCodeTable, nbSeq,
+ LL_defaultNorm, LL_defaultNormLog, MaxLL,
+ prevEntropy->litlengthCTable,
+ sizeof(prevEntropy->litlengthCTable),
+ entropyWorkspace, entropyWkspSize);
+ if (ZSTD_isError(countSize)) {
+ DEBUGLOG(3, "ZSTD_buildCTable for LitLens failed");
+ stats.size = countSize;
+ return stats;
+ }
+ if (stats.LLtype == set_compressed)
+ stats.lastCountSize = countSize;
+ op += countSize;
+ assert(op <= oend);
+ } }
+ /* build CTable for Offsets */
+ { unsigned max = MaxOff;
+ size_t const mostFrequent = HIST_countFast_wksp(
+ countWorkspace, &max, ofCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */
+ /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */
+ ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed;
+ DEBUGLOG(5, "Building OF table");
+ nextEntropy->offcode_repeatMode = prevEntropy->offcode_repeatMode;
+ stats.Offtype = ZSTD_selectEncodingType(&nextEntropy->offcode_repeatMode,
+ countWorkspace, max, mostFrequent, nbSeq,
+ OffFSELog, prevEntropy->offcodeCTable,
+ OF_defaultNorm, OF_defaultNormLog,
+ defaultPolicy, strategy);
+ assert(!(stats.Offtype < set_compressed && nextEntropy->offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */
+ { size_t const countSize = ZSTD_buildCTable(
+ op, (size_t)(oend - op),
+ CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)stats.Offtype,
+ countWorkspace, max, ofCodeTable, nbSeq,
+ OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
+ prevEntropy->offcodeCTable,
+ sizeof(prevEntropy->offcodeCTable),
+ entropyWorkspace, entropyWkspSize);
+ if (ZSTD_isError(countSize)) {
+ DEBUGLOG(3, "ZSTD_buildCTable for Offsets failed");
+ stats.size = countSize;
+ return stats;
+ }
+ if (stats.Offtype == set_compressed)
+ stats.lastCountSize = countSize;
+ op += countSize;
+ assert(op <= oend);
+ } }
+ /* build CTable for MatchLengths */
+ { unsigned max = MaxML;
+ size_t const mostFrequent = HIST_countFast_wksp(
+ countWorkspace, &max, mlCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */
+ DEBUGLOG(5, "Building ML table (remaining space : %i)", (int)(oend-op));
+ nextEntropy->matchlength_repeatMode = prevEntropy->matchlength_repeatMode;
+ stats.MLtype = ZSTD_selectEncodingType(&nextEntropy->matchlength_repeatMode,
+ countWorkspace, max, mostFrequent, nbSeq,
+ MLFSELog, prevEntropy->matchlengthCTable,
+ ML_defaultNorm, ML_defaultNormLog,
+ ZSTD_defaultAllowed, strategy);
+ assert(!(stats.MLtype < set_compressed && nextEntropy->matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
+ { size_t const countSize = ZSTD_buildCTable(
+ op, (size_t)(oend - op),
+ CTable_MatchLength, MLFSELog, (symbolEncodingType_e)stats.MLtype,
+ countWorkspace, max, mlCodeTable, nbSeq,
+ ML_defaultNorm, ML_defaultNormLog, MaxML,
+ prevEntropy->matchlengthCTable,
+ sizeof(prevEntropy->matchlengthCTable),
+ entropyWorkspace, entropyWkspSize);
+ if (ZSTD_isError(countSize)) {
+ DEBUGLOG(3, "ZSTD_buildCTable for MatchLengths failed");
+ stats.size = countSize;
+ return stats;
+ }
+ if (stats.MLtype == set_compressed)
+ stats.lastCountSize = countSize;
+ op += countSize;
+ assert(op <= oend);
+ } }
+ stats.size = (size_t)(op-ostart);
+ return stats;
+}
+
+/* ZSTD_entropyCompressSeqStore_internal():
+ * compresses both literals and sequences
+ * Returns compressed size of block, or a zstd error.
+ */
MEM_STATIC size_t
-ZSTD_entropyCompressSequences_internal(seqStore_t* seqStorePtr,
+ZSTD_entropyCompressSeqStore_internal(seqStore_t* seqStorePtr,
const ZSTD_entropyCTables_t* prevEntropy,
ZSTD_entropyCTables_t* nextEntropy,
const ZSTD_CCtx_params* cctxParams,
@@ -2161,22 +2561,20 @@ ZSTD_entropyCompressSequences_internal(seqStore_t* seqStorePtr,
FSE_CTable* CTable_LitLength = nextEntropy->fse.litlengthCTable;
FSE_CTable* CTable_OffsetBits = nextEntropy->fse.offcodeCTable;
FSE_CTable* CTable_MatchLength = nextEntropy->fse.matchlengthCTable;
- U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
const seqDef* const sequences = seqStorePtr->sequencesStart;
+ const size_t nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
const BYTE* const ofCodeTable = seqStorePtr->ofCode;
const BYTE* const llCodeTable = seqStorePtr->llCode;
const BYTE* const mlCodeTable = seqStorePtr->mlCode;
BYTE* const ostart = (BYTE*)dst;
BYTE* const oend = ostart + dstCapacity;
BYTE* op = ostart;
- size_t const nbSeq = (size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
- BYTE* seqHead;
- BYTE* lastNCount = NULL;
+ size_t lastCountSize;
entropyWorkspace = count + (MaxSeq + 1);
entropyWkspSize -= (MaxSeq + 1) * sizeof(*count);
- DEBUGLOG(4, "ZSTD_entropyCompressSequences_internal (nbSeq=%zu)", nbSeq);
+ DEBUGLOG(4, "ZSTD_entropyCompressSeqStore_internal (nbSeq=%zu)", nbSeq);
ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog)));
assert(entropyWkspSize >= HUF_WORKSPACE_SIZE);
@@ -2216,95 +2614,20 @@ ZSTD_entropyCompressSequences_internal(seqStore_t* seqStorePtr,
ZSTD_memcpy(&nextEntropy->fse, &prevEntropy->fse, sizeof(prevEntropy->fse));
return (size_t)(op - ostart);
}
-
- /* seqHead : flags for FSE encoding type */
- seqHead = op++;
- assert(op <= oend);
-
- /* convert length/distances into codes */
- ZSTD_seqToCodes(seqStorePtr);
- /* build CTable for Literal Lengths */
- { unsigned max = MaxLL;
- size_t const mostFrequent = HIST_countFast_wksp(count, &max, llCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */
- DEBUGLOG(5, "Building LL table");
- nextEntropy->fse.litlength_repeatMode = prevEntropy->fse.litlength_repeatMode;
- LLtype = ZSTD_selectEncodingType(&nextEntropy->fse.litlength_repeatMode,
- count, max, mostFrequent, nbSeq,
- LLFSELog, prevEntropy->fse.litlengthCTable,
- LL_defaultNorm, LL_defaultNormLog,
- ZSTD_defaultAllowed, strategy);
- assert(set_basic < set_compressed && set_rle < set_compressed);
- assert(!(LLtype < set_compressed && nextEntropy->fse.litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
- { size_t const countSize = ZSTD_buildCTable(
- op, (size_t)(oend - op),
- CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype,
- count, max, llCodeTable, nbSeq,
- LL_defaultNorm, LL_defaultNormLog, MaxLL,
- prevEntropy->fse.litlengthCTable,
- sizeof(prevEntropy->fse.litlengthCTable),
- entropyWorkspace, entropyWkspSize);
- FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for LitLens failed");
- if (LLtype == set_compressed)
- lastNCount = op;
- op += countSize;
- assert(op <= oend);
- } }
- /* build CTable for Offsets */
- { unsigned max = MaxOff;
- size_t const mostFrequent = HIST_countFast_wksp(
- count, &max, ofCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */
- /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */
- ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed;
- DEBUGLOG(5, "Building OF table");
- nextEntropy->fse.offcode_repeatMode = prevEntropy->fse.offcode_repeatMode;
- Offtype = ZSTD_selectEncodingType(&nextEntropy->fse.offcode_repeatMode,
- count, max, mostFrequent, nbSeq,
- OffFSELog, prevEntropy->fse.offcodeCTable,
- OF_defaultNorm, OF_defaultNormLog,
- defaultPolicy, strategy);
- assert(!(Offtype < set_compressed && nextEntropy->fse.offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */
- { size_t const countSize = ZSTD_buildCTable(
- op, (size_t)(oend - op),
- CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype,
- count, max, ofCodeTable, nbSeq,
- OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
- prevEntropy->fse.offcodeCTable,
- sizeof(prevEntropy->fse.offcodeCTable),
- entropyWorkspace, entropyWkspSize);
- FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for Offsets failed");
- if (Offtype == set_compressed)
- lastNCount = op;
- op += countSize;
- assert(op <= oend);
- } }
- /* build CTable for MatchLengths */
- { unsigned max = MaxML;
- size_t const mostFrequent = HIST_countFast_wksp(
- count, &max, mlCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */
- DEBUGLOG(5, "Building ML table (remaining space : %i)", (int)(oend-op));
- nextEntropy->fse.matchlength_repeatMode = prevEntropy->fse.matchlength_repeatMode;
- MLtype = ZSTD_selectEncodingType(&nextEntropy->fse.matchlength_repeatMode,
- count, max, mostFrequent, nbSeq,
- MLFSELog, prevEntropy->fse.matchlengthCTable,
- ML_defaultNorm, ML_defaultNormLog,
- ZSTD_defaultAllowed, strategy);
- assert(!(MLtype < set_compressed && nextEntropy->fse.matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
- { size_t const countSize = ZSTD_buildCTable(
- op, (size_t)(oend - op),
- CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype,
- count, max, mlCodeTable, nbSeq,
- ML_defaultNorm, ML_defaultNormLog, MaxML,
- prevEntropy->fse.matchlengthCTable,
- sizeof(prevEntropy->fse.matchlengthCTable),
- entropyWorkspace, entropyWkspSize);
- FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for MatchLengths failed");
- if (MLtype == set_compressed)
- lastNCount = op;
- op += countSize;
- assert(op <= oend);
- } }
-
- *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
+ {
+ ZSTD_symbolEncodingTypeStats_t stats;
+ BYTE* seqHead = op++;
+ /* build stats for sequences */
+ stats = ZSTD_buildSequencesStatistics(seqStorePtr, nbSeq,
+ &prevEntropy->fse, &nextEntropy->fse,
+ op, oend,
+ strategy, count,
+ entropyWorkspace, entropyWkspSize);
+ FORWARD_IF_ERROR(stats.size, "ZSTD_buildSequencesStatistics failed!");
+ *seqHead = (BYTE)((stats.LLtype<<6) + (stats.Offtype<<4) + (stats.MLtype<<2));
+ lastCountSize = stats.lastCountSize;
+ op += stats.size;
+ }
{ size_t const bitstreamSize = ZSTD_encodeSequences(
op, (size_t)(oend - op),
@@ -2324,9 +2647,9 @@ ZSTD_entropyCompressSequences_internal(seqStore_t* seqStorePtr,
* In this exceedingly rare case, we will simply emit an uncompressed
* block, since it isn't worth optimizing.
*/
- if (lastNCount && (op - lastNCount) < 4) {
- /* NCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */
- assert(op - lastNCount == 3);
+ if (lastCountSize && (lastCountSize + bitstreamSize) < 4) {
+ /* lastCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */
+ assert(lastCountSize + bitstreamSize == 3);
DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.3.4 by "
"emitting an uncompressed block.");
return 0;
@@ -2338,7 +2661,7 @@ ZSTD_entropyCompressSequences_internal(seqStore_t* seqStorePtr,
}
MEM_STATIC size_t
-ZSTD_entropyCompressSequences(seqStore_t* seqStorePtr,
+ZSTD_entropyCompressSeqStore(seqStore_t* seqStorePtr,
const ZSTD_entropyCTables_t* prevEntropy,
ZSTD_entropyCTables_t* nextEntropy,
const ZSTD_CCtx_params* cctxParams,
@@ -2347,7 +2670,7 @@ ZSTD_entropyCompressSequences(seqStore_t* seqStorePtr,
void* entropyWorkspace, size_t entropyWkspSize,
int bmi2)
{
- size_t const cSize = ZSTD_entropyCompressSequences_internal(
+ size_t const cSize = ZSTD_entropyCompressSeqStore_internal(
seqStorePtr, prevEntropy, nextEntropy, cctxParams,
dst, dstCapacity,
entropyWorkspace, entropyWkspSize, bmi2);
@@ -2357,20 +2680,20 @@ ZSTD_entropyCompressSequences(seqStore_t* seqStorePtr,
*/
if ((cSize == ERROR(dstSize_tooSmall)) & (srcSize <= dstCapacity))
return 0; /* block not compressed */
- FORWARD_IF_ERROR(cSize, "ZSTD_entropyCompressSequences_internal failed");
+ FORWARD_IF_ERROR(cSize, "ZSTD_entropyCompressSeqStore_internal failed");
/* Check compressibility */
{ size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, cctxParams->cParams.strategy);
if (cSize >= maxCSize) return 0; /* block not compressed */
}
- DEBUGLOG(4, "ZSTD_entropyCompressSequences() cSize: %zu\n", cSize);
+ DEBUGLOG(4, "ZSTD_entropyCompressSeqStore() cSize: %zu", cSize);
return cSize;
}
/* ZSTD_selectBlockCompressor() :
* Not static, but internal use only (used by long distance matcher)
* assumption : strat is a valid strategy */
-ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode)
+ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_useRowMatchFinderMode_e useRowMatchFinder, ZSTD_dictMode_e dictMode)
{
static const ZSTD_blockCompressor blockCompressor[4][ZSTD_STRATEGY_MAX+1] = {
{ ZSTD_compressBlock_fast /* default for 0 */,
@@ -2418,7 +2741,28 @@ ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMo
ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1);
assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, strat));
- selectedCompressor = blockCompressor[(int)dictMode][(int)strat];
+ DEBUGLOG(4, "Selected block compressor: dictMode=%d strat=%d rowMatchfinder=%d", (int)dictMode, (int)strat, (int)useRowMatchFinder);
+ if (ZSTD_rowMatchFinderUsed(strat, useRowMatchFinder)) {
+ static const ZSTD_blockCompressor rowBasedBlockCompressors[4][3] = {
+ { ZSTD_compressBlock_greedy_row,
+ ZSTD_compressBlock_lazy_row,
+ ZSTD_compressBlock_lazy2_row },
+ { ZSTD_compressBlock_greedy_extDict_row,
+ ZSTD_compressBlock_lazy_extDict_row,
+ ZSTD_compressBlock_lazy2_extDict_row },
+ { ZSTD_compressBlock_greedy_dictMatchState_row,
+ ZSTD_compressBlock_lazy_dictMatchState_row,
+ ZSTD_compressBlock_lazy2_dictMatchState_row },
+ { ZSTD_compressBlock_greedy_dedicatedDictSearch_row,
+ ZSTD_compressBlock_lazy_dedicatedDictSearch_row,
+ ZSTD_compressBlock_lazy2_dedicatedDictSearch_row }
+ };
+ DEBUGLOG(4, "Selecting a row-based matchfinder");
+ assert(useRowMatchFinder != ZSTD_urm_auto);
+ selectedCompressor = rowBasedBlockCompressors[(int)dictMode][(int)strat - (int)ZSTD_greedy];
+ } else {
+ selectedCompressor = blockCompressor[(int)dictMode][(int)strat];
+ }
assert(selectedCompressor != NULL);
return selectedCompressor;
}
@@ -2434,7 +2778,7 @@ void ZSTD_resetSeqStore(seqStore_t* ssPtr)
{
ssPtr->lit = ssPtr->litStart;
ssPtr->sequences = ssPtr->sequencesStart;
- ssPtr->longLengthID = 0;
+ ssPtr->longLengthType = ZSTD_llt_none;
}
typedef enum { ZSTDbss_compress, ZSTDbss_noCompress } ZSTD_buildSeqStore_e;
@@ -2487,6 +2831,7 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize)
ZSTD_ldm_blockCompress(&zc->externSeqStore,
ms, &zc->seqStore,
zc->blockState.nextCBlock->rep,
+ zc->appliedParams.useRowMatchFinder,
src, srcSize);
assert(zc->externSeqStore.pos <= zc->externSeqStore.size);
} else if (zc->appliedParams.ldmParams.enableLdm) {
@@ -2503,10 +2848,13 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize)
ZSTD_ldm_blockCompress(&ldmSeqStore,
ms, &zc->seqStore,
zc->blockState.nextCBlock->rep,
+ zc->appliedParams.useRowMatchFinder,
src, srcSize);
assert(ldmSeqStore.pos == ldmSeqStore.size);
} else { /* not long range mode */
- ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, dictMode);
+ ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy,
+ zc->appliedParams.useRowMatchFinder,
+ dictMode);
ms->ldmSeqStore = NULL;
lastLLSize = blockCompressor(ms, &zc->seqStore, zc->blockState.nextCBlock->rep, src, srcSize);
}
@@ -2540,9 +2888,9 @@ static void ZSTD_copyBlockSequences(ZSTD_CCtx* zc)
outSeqs[i].rep = 0;
if (i == seqStore->longLengthPos) {
- if (seqStore->longLengthID == 1) {
+ if (seqStore->longLengthType == ZSTD_llt_literalLength) {
outSeqs[i].litLength += 0x10000;
- } else if (seqStore->longLengthID == 2) {
+ } else if (seqStore->longLengthType == ZSTD_llt_matchLength) {
outSeqs[i].matchLength += 0x10000;
}
}
@@ -2653,11 +3001,713 @@ static int ZSTD_maybeRLE(seqStore_t const* seqStore)
return nbSeqs < 4 && nbLits < 10;
}
-static void ZSTD_confirmRepcodesAndEntropyTables(ZSTD_CCtx* zc)
+static void ZSTD_blockState_confirmRepcodesAndEntropyTables(ZSTD_blockState_t* const bs)
{
- ZSTD_compressedBlockState_t* const tmp = zc->blockState.prevCBlock;
- zc->blockState.prevCBlock = zc->blockState.nextCBlock;
- zc->blockState.nextCBlock = tmp;
+ ZSTD_compressedBlockState_t* const tmp = bs->prevCBlock;
+ bs->prevCBlock = bs->nextCBlock;
+ bs->nextCBlock = tmp;
+}
+
+/* Writes the block header */
+static void writeBlockHeader(void* op, size_t cSize, size_t blockSize, U32 lastBlock) {
+ U32 const cBlockHeader = cSize == 1 ?
+ lastBlock + (((U32)bt_rle)<<1) + (U32)(blockSize << 3) :
+ lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
+ MEM_writeLE24(op, cBlockHeader);
+ DEBUGLOG(3, "writeBlockHeader: cSize: %zu blockSize: %zu lastBlock: %u", cSize, blockSize, lastBlock);
+}
+
+/** ZSTD_buildBlockEntropyStats_literals() :
+ * Builds entropy for the literals.
+ * Stores literals block type (raw, rle, compressed, repeat) and
+ * huffman description table to hufMetadata.
+ * Requires ENTROPY_WORKSPACE_SIZE workspace
+ * @return : size of huffman description table or error code */
+static size_t ZSTD_buildBlockEntropyStats_literals(void* const src, size_t srcSize,
+ const ZSTD_hufCTables_t* prevHuf,
+ ZSTD_hufCTables_t* nextHuf,
+ ZSTD_hufCTablesMetadata_t* hufMetadata,
+ const int disableLiteralsCompression,
+ void* workspace, size_t wkspSize)
+{
+ BYTE* const wkspStart = (BYTE*)workspace;
+ BYTE* const wkspEnd = wkspStart + wkspSize;
+ BYTE* const countWkspStart = wkspStart;
+ unsigned* const countWksp = (unsigned*)workspace;
+ const size_t countWkspSize = (HUF_SYMBOLVALUE_MAX + 1) * sizeof(unsigned);
+ BYTE* const nodeWksp = countWkspStart + countWkspSize;
+ const size_t nodeWkspSize = wkspEnd-nodeWksp;
+ unsigned maxSymbolValue = HUF_SYMBOLVALUE_MAX;
+ unsigned huffLog = HUF_TABLELOG_DEFAULT;
+ HUF_repeat repeat = prevHuf->repeatMode;
+ DEBUGLOG(5, "ZSTD_buildBlockEntropyStats_literals (srcSize=%zu)", srcSize);
+
+ /* Prepare nextEntropy assuming reusing the existing table */
+ ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
+
+ if (disableLiteralsCompression) {
+ DEBUGLOG(5, "set_basic - disabled");
+ hufMetadata->hType = set_basic;
+ return 0;
+ }
+
+ /* small ? don't even attempt compression (speed opt) */
+#ifndef COMPRESS_LITERALS_SIZE_MIN
+#define COMPRESS_LITERALS_SIZE_MIN 63
+#endif
+ { size_t const minLitSize = (prevHuf->repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN;
+ if (srcSize <= minLitSize) {
+ DEBUGLOG(5, "set_basic - too small");
+ hufMetadata->hType = set_basic;
+ return 0;
+ }
+ }
+
+ /* Scan input and build symbol stats */
+ { size_t const largest = HIST_count_wksp (countWksp, &maxSymbolValue, (const BYTE*)src, srcSize, workspace, wkspSize);
+ FORWARD_IF_ERROR(largest, "HIST_count_wksp failed");
+ if (largest == srcSize) {
+ DEBUGLOG(5, "set_rle");
+ hufMetadata->hType = set_rle;
+ return 0;
+ }
+ if (largest <= (srcSize >> 7)+4) {
+ DEBUGLOG(5, "set_basic - no gain");
+ hufMetadata->hType = set_basic;
+ return 0;
+ }
+ }
+
+ /* Validate the previous Huffman table */
+ if (repeat == HUF_repeat_check && !HUF_validateCTable((HUF_CElt const*)prevHuf->CTable, countWksp, maxSymbolValue)) {
+ repeat = HUF_repeat_none;
+ }
+
+ /* Build Huffman Tree */
+ ZSTD_memset(nextHuf->CTable, 0, sizeof(nextHuf->CTable));
+ huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue);
+ { size_t const maxBits = HUF_buildCTable_wksp((HUF_CElt*)nextHuf->CTable, countWksp,
+ maxSymbolValue, huffLog,
+ nodeWksp, nodeWkspSize);
+ FORWARD_IF_ERROR(maxBits, "HUF_buildCTable_wksp");
+ huffLog = (U32)maxBits;
+ { /* Build and write the CTable */
+ size_t const newCSize = HUF_estimateCompressedSize(
+ (HUF_CElt*)nextHuf->CTable, countWksp, maxSymbolValue);
+ size_t const hSize = HUF_writeCTable_wksp(
+ hufMetadata->hufDesBuffer, sizeof(hufMetadata->hufDesBuffer),
+ (HUF_CElt*)nextHuf->CTable, maxSymbolValue, huffLog,
+ nodeWksp, nodeWkspSize);
+ /* Check against repeating the previous CTable */
+ if (repeat != HUF_repeat_none) {
+ size_t const oldCSize = HUF_estimateCompressedSize(
+ (HUF_CElt const*)prevHuf->CTable, countWksp, maxSymbolValue);
+ if (oldCSize < srcSize && (oldCSize <= hSize + newCSize || hSize + 12 >= srcSize)) {
+ DEBUGLOG(5, "set_repeat - smaller");
+ ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
+ hufMetadata->hType = set_repeat;
+ return 0;
+ }
+ }
+ if (newCSize + hSize >= srcSize) {
+ DEBUGLOG(5, "set_basic - no gains");
+ ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
+ hufMetadata->hType = set_basic;
+ return 0;
+ }
+ DEBUGLOG(5, "set_compressed (hSize=%u)", (U32)hSize);
+ hufMetadata->hType = set_compressed;
+ nextHuf->repeatMode = HUF_repeat_check;
+ return hSize;
+ }
+ }
+}
+
+
+/* ZSTD_buildDummySequencesStatistics():
+ * Returns a ZSTD_symbolEncodingTypeStats_t with all encoding types as set_basic,
+ * and updates nextEntropy to the appropriate repeatMode.
+ */
+static ZSTD_symbolEncodingTypeStats_t
+ZSTD_buildDummySequencesStatistics(ZSTD_fseCTables_t* nextEntropy) {
+ ZSTD_symbolEncodingTypeStats_t stats = {set_basic, set_basic, set_basic, 0, 0};
+ nextEntropy->litlength_repeatMode = FSE_repeat_none;
+ nextEntropy->offcode_repeatMode = FSE_repeat_none;
+ nextEntropy->matchlength_repeatMode = FSE_repeat_none;
+ return stats;
+}
+
+/** ZSTD_buildBlockEntropyStats_sequences() :
+ * Builds entropy for the sequences.
+ * Stores symbol compression modes and fse table to fseMetadata.
+ * Requires ENTROPY_WORKSPACE_SIZE wksp.
+ * @return : size of fse tables or error code */
+static size_t ZSTD_buildBlockEntropyStats_sequences(seqStore_t* seqStorePtr,
+ const ZSTD_fseCTables_t* prevEntropy,
+ ZSTD_fseCTables_t* nextEntropy,
+ const ZSTD_CCtx_params* cctxParams,
+ ZSTD_fseCTablesMetadata_t* fseMetadata,
+ void* workspace, size_t wkspSize)
+{
+ ZSTD_strategy const strategy = cctxParams->cParams.strategy;
+ size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
+ BYTE* const ostart = fseMetadata->fseTablesBuffer;
+ BYTE* const oend = ostart + sizeof(fseMetadata->fseTablesBuffer);
+ BYTE* op = ostart;
+ unsigned* countWorkspace = (unsigned*)workspace;
+ unsigned* entropyWorkspace = countWorkspace + (MaxSeq + 1);
+ size_t entropyWorkspaceSize = wkspSize - (MaxSeq + 1) * sizeof(*countWorkspace);
+ ZSTD_symbolEncodingTypeStats_t stats;
+
+ DEBUGLOG(5, "ZSTD_buildBlockEntropyStats_sequences (nbSeq=%zu)", nbSeq);
+ stats = nbSeq != 0 ? ZSTD_buildSequencesStatistics(seqStorePtr, nbSeq,
+ prevEntropy, nextEntropy, op, oend,
+ strategy, countWorkspace,
+ entropyWorkspace, entropyWorkspaceSize)
+ : ZSTD_buildDummySequencesStatistics(nextEntropy);
+ FORWARD_IF_ERROR(stats.size, "ZSTD_buildSequencesStatistics failed!");
+ fseMetadata->llType = (symbolEncodingType_e) stats.LLtype;
+ fseMetadata->ofType = (symbolEncodingType_e) stats.Offtype;
+ fseMetadata->mlType = (symbolEncodingType_e) stats.MLtype;
+ fseMetadata->lastCountSize = stats.lastCountSize;
+ return stats.size;
+}
+
+
+/** ZSTD_buildBlockEntropyStats() :
+ * Builds entropy for the block.
+ * Requires workspace size ENTROPY_WORKSPACE_SIZE
+ *
+ * @return : 0 on success or error code
+ */
+size_t ZSTD_buildBlockEntropyStats(seqStore_t* seqStorePtr,
+ const ZSTD_entropyCTables_t* prevEntropy,
+ ZSTD_entropyCTables_t* nextEntropy,
+ const ZSTD_CCtx_params* cctxParams,
+ ZSTD_entropyCTablesMetadata_t* entropyMetadata,
+ void* workspace, size_t wkspSize)
+{
+ size_t const litSize = seqStorePtr->lit - seqStorePtr->litStart;
+ entropyMetadata->hufMetadata.hufDesSize =
+ ZSTD_buildBlockEntropyStats_literals(seqStorePtr->litStart, litSize,
+ &prevEntropy->huf, &nextEntropy->huf,
+ &entropyMetadata->hufMetadata,
+ ZSTD_disableLiteralsCompression(cctxParams),
+ workspace, wkspSize);
+ FORWARD_IF_ERROR(entropyMetadata->hufMetadata.hufDesSize, "ZSTD_buildBlockEntropyStats_literals failed");
+ entropyMetadata->fseMetadata.fseTablesSize =
+ ZSTD_buildBlockEntropyStats_sequences(seqStorePtr,
+ &prevEntropy->fse, &nextEntropy->fse,
+ cctxParams,
+ &entropyMetadata->fseMetadata,
+ workspace, wkspSize);
+ FORWARD_IF_ERROR(entropyMetadata->fseMetadata.fseTablesSize, "ZSTD_buildBlockEntropyStats_sequences failed");
+ return 0;
+}
+
+/* Returns the size estimate for the literals section (header + content) of a block */
+static size_t ZSTD_estimateBlockSize_literal(const BYTE* literals, size_t litSize,
+ const ZSTD_hufCTables_t* huf,
+ const ZSTD_hufCTablesMetadata_t* hufMetadata,
+ void* workspace, size_t wkspSize,
+ int writeEntropy)
+{
+ unsigned* const countWksp = (unsigned*)workspace;
+ unsigned maxSymbolValue = HUF_SYMBOLVALUE_MAX;
+ size_t literalSectionHeaderSize = 3 + (litSize >= 1 KB) + (litSize >= 16 KB);
+ U32 singleStream = litSize < 256;
+
+ if (hufMetadata->hType == set_basic) return litSize;
+ else if (hufMetadata->hType == set_rle) return 1;
+ else if (hufMetadata->hType == set_compressed || hufMetadata->hType == set_repeat) {
+ size_t const largest = HIST_count_wksp (countWksp, &maxSymbolValue, (const BYTE*)literals, litSize, workspace, wkspSize);
+ if (ZSTD_isError(largest)) return litSize;
+ { size_t cLitSizeEstimate = HUF_estimateCompressedSize((const HUF_CElt*)huf->CTable, countWksp, maxSymbolValue);
+ if (writeEntropy) cLitSizeEstimate += hufMetadata->hufDesSize;
+ if (!singleStream) cLitSizeEstimate += 6; /* multi-stream huffman uses 6-byte jump table */
+ return cLitSizeEstimate + literalSectionHeaderSize;
+ } }
+ assert(0); /* impossible */
+ return 0;
+}
+
+/* Returns the size estimate for the FSE-compressed symbols (of, ml, ll) of a block */
+static size_t ZSTD_estimateBlockSize_symbolType(symbolEncodingType_e type,
+ const BYTE* codeTable, size_t nbSeq, unsigned maxCode,
+ const FSE_CTable* fseCTable,
+ const U32* additionalBits,
+ short const* defaultNorm, U32 defaultNormLog, U32 defaultMax,
+ void* workspace, size_t wkspSize)
+{
+ unsigned* const countWksp = (unsigned*)workspace;
+ const BYTE* ctp = codeTable;
+ const BYTE* const ctStart = ctp;
+ const BYTE* const ctEnd = ctStart + nbSeq;
+ size_t cSymbolTypeSizeEstimateInBits = 0;
+ unsigned max = maxCode;
+
+ HIST_countFast_wksp(countWksp, &max, codeTable, nbSeq, workspace, wkspSize); /* can't fail */
+ if (type == set_basic) {
+ /* We selected this encoding type, so it must be valid. */
+ assert(max <= defaultMax);
+ (void)defaultMax;
+ cSymbolTypeSizeEstimateInBits = ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, countWksp, max);
+ } else if (type == set_rle) {
+ cSymbolTypeSizeEstimateInBits = 0;
+ } else if (type == set_compressed || type == set_repeat) {
+ cSymbolTypeSizeEstimateInBits = ZSTD_fseBitCost(fseCTable, countWksp, max);
+ }
+ if (ZSTD_isError(cSymbolTypeSizeEstimateInBits)) {
+ return nbSeq * 10;
+ }
+ while (ctp < ctEnd) {
+ if (additionalBits) cSymbolTypeSizeEstimateInBits += additionalBits[*ctp];
+ else cSymbolTypeSizeEstimateInBits += *ctp; /* for offset, offset code is also the number of additional bits */
+ ctp++;
+ }
+ return cSymbolTypeSizeEstimateInBits >> 3;
+}
+
+/* Returns the size estimate for the sequences section (header + content) of a block */
+static size_t ZSTD_estimateBlockSize_sequences(const BYTE* ofCodeTable,
+ const BYTE* llCodeTable,
+ const BYTE* mlCodeTable,
+ size_t nbSeq,
+ const ZSTD_fseCTables_t* fseTables,
+ const ZSTD_fseCTablesMetadata_t* fseMetadata,
+ void* workspace, size_t wkspSize,
+ int writeEntropy)
+{
+ size_t sequencesSectionHeaderSize = 1 /* seqHead */ + 1 /* min seqSize size */ + (nbSeq >= 128) + (nbSeq >= LONGNBSEQ);
+ size_t cSeqSizeEstimate = 0;
+ cSeqSizeEstimate += ZSTD_estimateBlockSize_symbolType(fseMetadata->ofType, ofCodeTable, nbSeq, MaxOff,
+ fseTables->offcodeCTable, NULL,
+ OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
+ workspace, wkspSize);
+ cSeqSizeEstimate += ZSTD_estimateBlockSize_symbolType(fseMetadata->llType, llCodeTable, nbSeq, MaxLL,
+ fseTables->litlengthCTable, LL_bits,
+ LL_defaultNorm, LL_defaultNormLog, MaxLL,
+ workspace, wkspSize);
+ cSeqSizeEstimate += ZSTD_estimateBlockSize_symbolType(fseMetadata->mlType, mlCodeTable, nbSeq, MaxML,
+ fseTables->matchlengthCTable, ML_bits,
+ ML_defaultNorm, ML_defaultNormLog, MaxML,
+ workspace, wkspSize);
+ if (writeEntropy) cSeqSizeEstimate += fseMetadata->fseTablesSize;
+ return cSeqSizeEstimate + sequencesSectionHeaderSize;
+}
+
+/* Returns the size estimate for a given stream of literals, of, ll, ml */
+static size_t ZSTD_estimateBlockSize(const BYTE* literals, size_t litSize,
+ const BYTE* ofCodeTable,
+ const BYTE* llCodeTable,
+ const BYTE* mlCodeTable,
+ size_t nbSeq,
+ const ZSTD_entropyCTables_t* entropy,
+ const ZSTD_entropyCTablesMetadata_t* entropyMetadata,
+ void* workspace, size_t wkspSize,
+ int writeLitEntropy, int writeSeqEntropy) {
+ size_t const literalsSize = ZSTD_estimateBlockSize_literal(literals, litSize,
+ &entropy->huf, &entropyMetadata->hufMetadata,
+ workspace, wkspSize, writeLitEntropy);
+ size_t const seqSize = ZSTD_estimateBlockSize_sequences(ofCodeTable, llCodeTable, mlCodeTable,
+ nbSeq, &entropy->fse, &entropyMetadata->fseMetadata,
+ workspace, wkspSize, writeSeqEntropy);
+ return seqSize + literalsSize + ZSTD_blockHeaderSize;
+}
+
+/* Builds entropy statistics and uses them for blocksize estimation.
+ *
+ * Returns the estimated compressed size of the seqStore, or a zstd error.
+ */
+static size_t ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(seqStore_t* seqStore, const ZSTD_CCtx* zc) {
+ ZSTD_entropyCTablesMetadata_t entropyMetadata;
+ FORWARD_IF_ERROR(ZSTD_buildBlockEntropyStats(seqStore,
+ &zc->blockState.prevCBlock->entropy,
+ &zc->blockState.nextCBlock->entropy,
+ &zc->appliedParams,
+ &entropyMetadata,
+ zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */), "");
+ return ZSTD_estimateBlockSize(seqStore->litStart, (size_t)(seqStore->lit - seqStore->litStart),
+ seqStore->ofCode, seqStore->llCode, seqStore->mlCode,
+ (size_t)(seqStore->sequences - seqStore->sequencesStart),
+ &zc->blockState.nextCBlock->entropy, &entropyMetadata, zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE,
+ (int)(entropyMetadata.hufMetadata.hType == set_compressed), 1);
+}
+
+/* Returns literals bytes represented in a seqStore */
+static size_t ZSTD_countSeqStoreLiteralsBytes(const seqStore_t* const seqStore) {
+ size_t literalsBytes = 0;
+ size_t const nbSeqs = seqStore->sequences - seqStore->sequencesStart;
+ size_t i;
+ for (i = 0; i < nbSeqs; ++i) {
+ seqDef seq = seqStore->sequencesStart[i];
+ literalsBytes += seq.litLength;
+ if (i == seqStore->longLengthPos && seqStore->longLengthType == ZSTD_llt_literalLength) {
+ literalsBytes += 0x10000;
+ }
+ }
+ return literalsBytes;
+}
+
+/* Returns match bytes represented in a seqStore */
+static size_t ZSTD_countSeqStoreMatchBytes(const seqStore_t* const seqStore) {
+ size_t matchBytes = 0;
+ size_t const nbSeqs = seqStore->sequences - seqStore->sequencesStart;
+ size_t i;
+ for (i = 0; i < nbSeqs; ++i) {
+ seqDef seq = seqStore->sequencesStart[i];
+ matchBytes += seq.matchLength + MINMATCH;
+ if (i == seqStore->longLengthPos && seqStore->longLengthType == ZSTD_llt_matchLength) {
+ matchBytes += 0x10000;
+ }
+ }
+ return matchBytes;
+}
+
+/* Derives the seqStore that is a chunk of the originalSeqStore from [startIdx, endIdx).
+ * Stores the result in resultSeqStore.
+ */
+static void ZSTD_deriveSeqStoreChunk(seqStore_t* resultSeqStore,
+ const seqStore_t* originalSeqStore,
+ size_t startIdx, size_t endIdx) {
+ BYTE* const litEnd = originalSeqStore->lit;
+ size_t literalsBytes;
+ size_t literalsBytesPreceding = 0;
+
+ *resultSeqStore = *originalSeqStore;
+ if (startIdx > 0) {
+ resultSeqStore->sequences = originalSeqStore->sequencesStart + startIdx;
+ literalsBytesPreceding = ZSTD_countSeqStoreLiteralsBytes(resultSeqStore);
+ }
+
+ /* Move longLengthPos into the correct position if necessary */
+ if (originalSeqStore->longLengthType != ZSTD_llt_none) {
+ if (originalSeqStore->longLengthPos < startIdx || originalSeqStore->longLengthPos > endIdx) {
+ resultSeqStore->longLengthType = ZSTD_llt_none;
+ } else {
+ resultSeqStore->longLengthPos -= (U32)startIdx;
+ }
+ }
+ resultSeqStore->sequencesStart = originalSeqStore->sequencesStart + startIdx;
+ resultSeqStore->sequences = originalSeqStore->sequencesStart + endIdx;
+ literalsBytes = ZSTD_countSeqStoreLiteralsBytes(resultSeqStore);
+ resultSeqStore->litStart += literalsBytesPreceding;
+ if (endIdx == (size_t)(originalSeqStore->sequences - originalSeqStore->sequencesStart)) {
+ /* This accounts for possible last literals if the derived chunk reaches the end of the block */
+ resultSeqStore->lit = litEnd;
+ } else {
+ resultSeqStore->lit = resultSeqStore->litStart+literalsBytes;
+ }
+ resultSeqStore->llCode += startIdx;
+ resultSeqStore->mlCode += startIdx;
+ resultSeqStore->ofCode += startIdx;
+}
+
+/**
+ * Returns the raw offset represented by the combination of offCode, ll0, and repcode history.
+ * offCode must be an offCode representing a repcode, therefore in the range of [0, 2].
+ */
+static U32 ZSTD_resolveRepcodeToRawOffset(const U32 rep[ZSTD_REP_NUM], const U32 offCode, const U32 ll0) {
+ U32 const adjustedOffCode = offCode + ll0;
+ assert(offCode < ZSTD_REP_NUM);
+ if (adjustedOffCode == ZSTD_REP_NUM) {
+ /* litlength == 0 and offCode == 2 implies selection of first repcode - 1 */
+ assert(rep[0] > 0);
+ return rep[0] - 1;
+ }
+ return rep[adjustedOffCode];
+}
+
+/**
+ * ZSTD_seqStore_resolveOffCodes() reconciles any possible divergences in offset history that may arise
+ * due to emission of RLE/raw blocks that disturb the offset history, and replaces any repcodes within
+ * the seqStore that may be invalid.
+ *
+ * dRepcodes are updated as would be on the decompression side. cRepcodes are updated exactly in
+ * accordance with the seqStore.
+ */
+static void ZSTD_seqStore_resolveOffCodes(repcodes_t* const dRepcodes, repcodes_t* const cRepcodes,
+ seqStore_t* const seqStore, U32 const nbSeq) {
+ U32 idx = 0;
+ for (; idx < nbSeq; ++idx) {
+ seqDef* const seq = seqStore->sequencesStart + idx;
+ U32 const ll0 = (seq->litLength == 0);
+ U32 offCode = seq->offset - 1;
+ assert(seq->offset > 0);
+ if (offCode <= ZSTD_REP_MOVE) {
+ U32 const dRawOffset = ZSTD_resolveRepcodeToRawOffset(dRepcodes->rep, offCode, ll0);
+ U32 const cRawOffset = ZSTD_resolveRepcodeToRawOffset(cRepcodes->rep, offCode, ll0);
+ /* Adjust simulated decompression repcode history if we come across a mismatch. Replace
+ * the repcode with the offset it actually references, determined by the compression
+ * repcode history.
+ */
+ if (dRawOffset != cRawOffset) {
+ seq->offset = cRawOffset + ZSTD_REP_NUM;
+ }
+ }
+ /* Compression repcode history is always updated with values directly from the unmodified seqStore.
+ * Decompression repcode history may use modified seq->offset value taken from compression repcode history.
+ */
+ *dRepcodes = ZSTD_updateRep(dRepcodes->rep, seq->offset - 1, ll0);
+ *cRepcodes = ZSTD_updateRep(cRepcodes->rep, offCode, ll0);
+ }
+}
+
+/* ZSTD_compressSeqStore_singleBlock():
+ * Compresses a seqStore into a block with a block header, into the buffer dst.
+ *
+ * Returns the total size of that block (including header) or a ZSTD error code.
+ */
+static size_t ZSTD_compressSeqStore_singleBlock(ZSTD_CCtx* zc, seqStore_t* const seqStore,
+ repcodes_t* const dRep, repcodes_t* const cRep,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ U32 lastBlock, U32 isPartition) {
+ const U32 rleMaxLength = 25;
+ BYTE* op = (BYTE*)dst;
+ const BYTE* ip = (const BYTE*)src;
+ size_t cSize;
+ size_t cSeqsSize;
+
+ /* In case of an RLE or raw block, the simulated decompression repcode history must be reset */
+ repcodes_t const dRepOriginal = *dRep;
+ if (isPartition)
+ ZSTD_seqStore_resolveOffCodes(dRep, cRep, seqStore, (U32)(seqStore->sequences - seqStore->sequencesStart));
+
+ cSeqsSize = ZSTD_entropyCompressSeqStore(seqStore,
+ &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy,
+ &zc->appliedParams,
+ op + ZSTD_blockHeaderSize, dstCapacity - ZSTD_blockHeaderSize,
+ srcSize,
+ zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */,
+ zc->bmi2);
+ FORWARD_IF_ERROR(cSeqsSize, "ZSTD_entropyCompressSeqStore failed!");
+
+ if (!zc->isFirstBlock &&
+ cSeqsSize < rleMaxLength &&
+ ZSTD_isRLE((BYTE const*)src, srcSize)) {
+ /* We don't want to emit our first block as a RLE even if it qualifies because
+ * doing so will cause the decoder (cli only) to throw a "should consume all input error."
+ * This is only an issue for zstd <= v1.4.3
+ */
+ cSeqsSize = 1;
+ }
+
+ if (zc->seqCollector.collectSequences) {
+ ZSTD_copyBlockSequences(zc);
+ ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState);
+ return 0;
+ }
+
+ if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid)
+ zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check;
+
+ if (cSeqsSize == 0) {
+ cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, srcSize, lastBlock);
+ FORWARD_IF_ERROR(cSize, "Nocompress block failed");
+ DEBUGLOG(4, "Writing out nocompress block, size: %zu", cSize);
+ *dRep = dRepOriginal; /* reset simulated decompression repcode history */
+ } else if (cSeqsSize == 1) {
+ cSize = ZSTD_rleCompressBlock(op, dstCapacity, *ip, srcSize, lastBlock);
+ FORWARD_IF_ERROR(cSize, "RLE compress block failed");
+ DEBUGLOG(4, "Writing out RLE block, size: %zu", cSize);
+ *dRep = dRepOriginal; /* reset simulated decompression repcode history */
+ } else {
+ ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState);
+ writeBlockHeader(op, cSeqsSize, srcSize, lastBlock);
+ cSize = ZSTD_blockHeaderSize + cSeqsSize;
+ DEBUGLOG(4, "Writing out compressed block, size: %zu", cSize);
+ }
+ return cSize;
+}
+
+/* Struct to keep track of where we are in our recursive calls. */
+typedef struct {
+ U32* splitLocations; /* Array of split indices */
+ size_t idx; /* The current index within splitLocations being worked on */
+} seqStoreSplits;
+
+#define MIN_SEQUENCES_BLOCK_SPLITTING 300
+#define MAX_NB_SPLITS 196
+
+/* Helper function to perform the recursive search for block splits.
+ * Estimates the cost of seqStore prior to split, and estimates the cost of splitting the sequences in half.
+ * If advantageous to split, then we recurse down the two sub-blocks. If not, or if an error occurred in estimation, then
+ * we do not recurse.
+ *
+ * Note: The recursion depth is capped by a heuristic minimum number of sequences, defined by MIN_SEQUENCES_BLOCK_SPLITTING.
+ * In theory, this means the absolute largest recursion depth is 10 == log2(maxNbSeqInBlock/MIN_SEQUENCES_BLOCK_SPLITTING).
+ * In practice, recursion depth usually doesn't go beyond 4.
+ *
+ * Furthermore, the number of splits is capped by MAX_NB_SPLITS. At MAX_NB_SPLITS == 196 with the current existing blockSize
+ * maximum of 128 KB, this value is actually impossible to reach.
+ */
+static void ZSTD_deriveBlockSplitsHelper(seqStoreSplits* splits, size_t startIdx, size_t endIdx,
+ const ZSTD_CCtx* zc, const seqStore_t* origSeqStore) {
+ seqStore_t fullSeqStoreChunk;
+ seqStore_t firstHalfSeqStore;
+ seqStore_t secondHalfSeqStore;
+ size_t estimatedOriginalSize;
+ size_t estimatedFirstHalfSize;
+ size_t estimatedSecondHalfSize;
+ size_t midIdx = (startIdx + endIdx)/2;
+
+ if (endIdx - startIdx < MIN_SEQUENCES_BLOCK_SPLITTING || splits->idx >= MAX_NB_SPLITS) {
+ return;
+ }
+ ZSTD_deriveSeqStoreChunk(&fullSeqStoreChunk, origSeqStore, startIdx, endIdx);
+ ZSTD_deriveSeqStoreChunk(&firstHalfSeqStore, origSeqStore, startIdx, midIdx);
+ ZSTD_deriveSeqStoreChunk(&secondHalfSeqStore, origSeqStore, midIdx, endIdx);
+ estimatedOriginalSize = ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(&fullSeqStoreChunk, zc);
+ estimatedFirstHalfSize = ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(&firstHalfSeqStore, zc);
+ estimatedSecondHalfSize = ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(&secondHalfSeqStore, zc);
+ DEBUGLOG(5, "Estimated original block size: %zu -- First half split: %zu -- Second half split: %zu",
+ estimatedOriginalSize, estimatedFirstHalfSize, estimatedSecondHalfSize);
+ if (ZSTD_isError(estimatedOriginalSize) || ZSTD_isError(estimatedFirstHalfSize) || ZSTD_isError(estimatedSecondHalfSize)) {
+ return;
+ }
+ if (estimatedFirstHalfSize + estimatedSecondHalfSize < estimatedOriginalSize) {
+ ZSTD_deriveBlockSplitsHelper(splits, startIdx, midIdx, zc, origSeqStore);
+ splits->splitLocations[splits->idx] = (U32)midIdx;
+ splits->idx++;
+ ZSTD_deriveBlockSplitsHelper(splits, midIdx, endIdx, zc, origSeqStore);
+ }
+}
+
+/* Base recursive function. Populates a table with intra-block partition indices that can improve compression ratio.
+ *
+ * Returns the number of splits made (which equals the size of the partition table - 1).
+ */
+static size_t ZSTD_deriveBlockSplits(ZSTD_CCtx* zc, U32 partitions[], U32 nbSeq) {
+ seqStoreSplits splits = {partitions, 0};
+ if (nbSeq <= 4) {
+ DEBUGLOG(4, "ZSTD_deriveBlockSplits: Too few sequences to split");
+ /* Refuse to try and split anything with less than 4 sequences */
+ return 0;
+ }
+ ZSTD_deriveBlockSplitsHelper(&splits, 0, nbSeq, zc, &zc->seqStore);
+ splits.splitLocations[splits.idx] = nbSeq;
+ DEBUGLOG(5, "ZSTD_deriveBlockSplits: final nb partitions: %zu", splits.idx+1);
+ return splits.idx;
+}
+
+/* ZSTD_compressBlock_splitBlock():
+ * Attempts to split a given block into multiple blocks to improve compression ratio.
+ *
+ * Returns combined size of all blocks (which includes headers), or a ZSTD error code.
+ */
+static size_t ZSTD_compressBlock_splitBlock_internal(ZSTD_CCtx* zc, void* dst, size_t dstCapacity,
+ const void* src, size_t blockSize, U32 lastBlock, U32 nbSeq) {
+ size_t cSize = 0;
+ const BYTE* ip = (const BYTE*)src;
+ BYTE* op = (BYTE*)dst;
+ U32 partitions[MAX_NB_SPLITS];
+ size_t i = 0;
+ size_t srcBytesTotal = 0;
+ size_t numSplits = ZSTD_deriveBlockSplits(zc, partitions, nbSeq);
+ seqStore_t nextSeqStore;
+ seqStore_t currSeqStore;
+
+ /* If a block is split and some partitions are emitted as RLE/uncompressed, then repcode history
+ * may become invalid. In order to reconcile potentially invalid repcodes, we keep track of two
+ * separate repcode histories that simulate repcode history on compression and decompression side,
+ * and use the histories to determine whether we must replace a particular repcode with its raw offset.
+ *
+ * 1) cRep gets updated for each partition, regardless of whether the block was emitted as uncompressed
+ * or RLE. This allows us to retrieve the offset value that an invalid repcode references within
+ * a nocompress/RLE block.
+ * 2) dRep gets updated only for compressed partitions, and when a repcode gets replaced, will use
+ * the replacement offset value rather than the original repcode to update the repcode history.
+ * dRep also will be the final repcode history sent to the next block.
+ *
+ * See ZSTD_seqStore_resolveOffCodes() for more details.
+ */
+ repcodes_t dRep;
+ repcodes_t cRep;
+ ZSTD_memcpy(dRep.rep, zc->blockState.prevCBlock->rep, sizeof(repcodes_t));
+ ZSTD_memcpy(cRep.rep, zc->blockState.prevCBlock->rep, sizeof(repcodes_t));
+
+ DEBUGLOG(4, "ZSTD_compressBlock_splitBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)",
+ (unsigned)dstCapacity, (unsigned)zc->blockState.matchState.window.dictLimit,
+ (unsigned)zc->blockState.matchState.nextToUpdate);
+
+ if (numSplits == 0) {
+ size_t cSizeSingleBlock = ZSTD_compressSeqStore_singleBlock(zc, &zc->seqStore,
+ &dRep, &cRep,
+ op, dstCapacity,
+ ip, blockSize,
+ lastBlock, 0 /* isPartition */);
+ FORWARD_IF_ERROR(cSizeSingleBlock, "Compressing single block from splitBlock_internal() failed!");
+ DEBUGLOG(5, "ZSTD_compressBlock_splitBlock_internal: No splits");
+ assert(cSizeSingleBlock <= ZSTD_BLOCKSIZE_MAX + ZSTD_blockHeaderSize);
+ return cSizeSingleBlock;
+ }
+
+ ZSTD_deriveSeqStoreChunk(&currSeqStore, &zc->seqStore, 0, partitions[0]);
+ for (i = 0; i <= numSplits; ++i) {
+ size_t srcBytes;
+ size_t cSizeChunk;
+ U32 const lastPartition = (i == numSplits);
+ U32 lastBlockEntireSrc = 0;
+
+ srcBytes = ZSTD_countSeqStoreLiteralsBytes(&currSeqStore) + ZSTD_countSeqStoreMatchBytes(&currSeqStore);
+ srcBytesTotal += srcBytes;
+ if (lastPartition) {
+ /* This is the final partition, need to account for possible last literals */
+ srcBytes += blockSize - srcBytesTotal;
+ lastBlockEntireSrc = lastBlock;
+ } else {
+ ZSTD_deriveSeqStoreChunk(&nextSeqStore, &zc->seqStore, partitions[i], partitions[i+1]);
+ }
+
+ cSizeChunk = ZSTD_compressSeqStore_singleBlock(zc, &currSeqStore,
+ &dRep, &cRep,
+ op, dstCapacity,
+ ip, srcBytes,
+ lastBlockEntireSrc, 1 /* isPartition */);
+ DEBUGLOG(5, "Estimated size: %zu actual size: %zu", ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(&currSeqStore, zc), cSizeChunk);
+ FORWARD_IF_ERROR(cSizeChunk, "Compressing chunk failed!");
+
+ ip += srcBytes;
+ op += cSizeChunk;
+ dstCapacity -= cSizeChunk;
+ cSize += cSizeChunk;
+ currSeqStore = nextSeqStore;
+ assert(cSizeChunk <= ZSTD_BLOCKSIZE_MAX + ZSTD_blockHeaderSize);
+ }
+ /* cRep and dRep may have diverged during the compression. If so, we use the dRep repcodes
+ * for the next block.
+ */
+ ZSTD_memcpy(zc->blockState.prevCBlock->rep, dRep.rep, sizeof(repcodes_t));
+ return cSize;
+}
+
+static size_t ZSTD_compressBlock_splitBlock(ZSTD_CCtx* zc,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize, U32 lastBlock) {
+ const BYTE* ip = (const BYTE*)src;
+ BYTE* op = (BYTE*)dst;
+ U32 nbSeq;
+ size_t cSize;
+ DEBUGLOG(4, "ZSTD_compressBlock_splitBlock");
+
+ { const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize);
+ FORWARD_IF_ERROR(bss, "ZSTD_buildSeqStore failed");
+ if (bss == ZSTDbss_noCompress) {
+ if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid)
+ zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check;
+ cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, srcSize, lastBlock);
+ FORWARD_IF_ERROR(cSize, "ZSTD_noCompressBlock failed");
+ DEBUGLOG(4, "ZSTD_compressBlock_splitBlock: Nocompress block");
+ return cSize;
+ }
+ nbSeq = (U32)(zc->seqStore.sequences - zc->seqStore.sequencesStart);
+ }
+
+ assert(zc->appliedParams.splitBlocks == 1);
+ cSize = ZSTD_compressBlock_splitBlock_internal(zc, dst, dstCapacity, src, srcSize, lastBlock, nbSeq);
+ FORWARD_IF_ERROR(cSize, "Splitting blocks failed!");
+ return cSize;
}
static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc,
@@ -2683,12 +3733,12 @@ static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc,
if (zc->seqCollector.collectSequences) {
ZSTD_copyBlockSequences(zc);
- ZSTD_confirmRepcodesAndEntropyTables(zc);
+ ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState);
return 0;
}
/* encode sequences and literals */
- cSize = ZSTD_entropyCompressSequences(&zc->seqStore,
+ cSize = ZSTD_entropyCompressSeqStore(&zc->seqStore,
&zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy,
&zc->appliedParams,
dst, dstCapacity,
@@ -2717,7 +3767,7 @@ static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc,
out:
if (!ZSTD_isError(cSize) && cSize > 1) {
- ZSTD_confirmRepcodesAndEntropyTables(zc);
+ ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState);
}
/* We check that dictionaries have offset codes available for the first
* block. After the first block, the offcode table might not have large
@@ -2770,7 +3820,7 @@ static size_t ZSTD_compressBlock_targetCBlockSize_body(ZSTD_CCtx* zc,
size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, zc->appliedParams.cParams.strategy);
FORWARD_IF_ERROR(cSize, "ZSTD_compressSuperBlock failed");
if (cSize != 0 && cSize < maxCSize + ZSTD_blockHeaderSize) {
- ZSTD_confirmRepcodesAndEntropyTables(zc);
+ ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState);
return cSize;
}
}
@@ -2810,9 +3860,9 @@ static void ZSTD_overflowCorrectIfNeeded(ZSTD_matchState_t* ms,
void const* ip,
void const* iend)
{
- if (ZSTD_window_needOverflowCorrection(ms->window, iend)) {
- U32 const maxDist = (U32)1 << params->cParams.windowLog;
- U32 const cycleLog = ZSTD_cycleLog(params->cParams.chainLog, params->cParams.strategy);
+ U32 const cycleLog = ZSTD_cycleLog(params->cParams.chainLog, params->cParams.strategy);
+ U32 const maxDist = (U32)1 << params->cParams.windowLog;
+ if (ZSTD_window_needOverflowCorrection(ms->window, cycleLog, maxDist, ms->loadedDictEnd, ip, iend)) {
U32 const correction = ZSTD_window_correctOverflow(&ms->window, cycleLog, maxDist, ip);
ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30);
ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30);
@@ -2835,7 +3885,7 @@ static void ZSTD_overflowCorrectIfNeeded(ZSTD_matchState_t* ms,
* Frame is supposed already started (header already produced)
* @return : compressed size, or an error code
*/
-static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
+static size_t ZSTD_compress_frameChunk(ZSTD_CCtx* cctx,
void* dst, size_t dstCapacity,
const void* src, size_t srcSize,
U32 lastFrameChunk)
@@ -2875,6 +3925,10 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_targetCBlockSize failed");
assert(cSize > 0);
assert(cSize <= blockSize + ZSTD_blockHeaderSize);
+ } else if (ZSTD_blockSplitterEnabled(&cctx->appliedParams)) {
+ cSize = ZSTD_compressBlock_splitBlock(cctx, op, dstCapacity, ip, blockSize, lastBlock);
+ FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_splitBlock failed");
+ assert(cSize > 0 || cctx->seqCollector.collectSequences == 1);
} else {
cSize = ZSTD_compressBlock_internal(cctx,
op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize,
@@ -2954,6 +4008,26 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
return pos;
}
+/* ZSTD_writeSkippableFrame_advanced() :
+ * Writes out a skippable frame with the specified magic number variant (16 are supported),
+ * from ZSTD_MAGIC_SKIPPABLE_START to ZSTD_MAGIC_SKIPPABLE_START+15, and the desired source data.
+ *
+ * Returns the total number of bytes written, or a ZSTD error code.
+ */
+size_t ZSTD_writeSkippableFrame(void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize, unsigned magicVariant) {
+ BYTE* op = (BYTE*)dst;
+ RETURN_ERROR_IF(dstCapacity < srcSize + ZSTD_SKIPPABLEHEADERSIZE /* Skippable frame overhead */,
+ dstSize_tooSmall, "Not enough room for skippable frame");
+ RETURN_ERROR_IF(srcSize > (unsigned)0xFFFFFFFF, srcSize_wrong, "Src size too large for skippable frame");
+ RETURN_ERROR_IF(magicVariant > 15, parameter_outOfBound, "Skippable frame magic number variant not supported");
+
+ MEM_writeLE32(op, (U32)(ZSTD_MAGIC_SKIPPABLE_START + magicVariant));
+ MEM_writeLE32(op+4, (U32)srcSize);
+ ZSTD_memcpy(op+8, src, srcSize);
+ return srcSize + ZSTD_SKIPPABLEHEADERSIZE;
+}
+
/* ZSTD_writeLastEmptyBlock() :
* output an empty Block with end-of-frame mark to complete a frame
* @return : size of data written into `dst` (== ZSTD_blockHeaderSize (defined in zstd_internal.h))
@@ -3010,11 +4084,12 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
if (!srcSize) return fhSize; /* do not generate an empty block if no input */
- if (!ZSTD_window_update(&ms->window, src, srcSize)) {
+ if (!ZSTD_window_update(&ms->window, src, srcSize, ms->forceNonContiguous)) {
+ ms->forceNonContiguous = 0;
ms->nextToUpdate = ms->window.dictLimit;
}
if (cctx->appliedParams.ldmParams.enableLdm) {
- ZSTD_window_update(&cctx->ldmState.window, src, srcSize);
+ ZSTD_window_update(&cctx->ldmState.window, src, srcSize, /* forceNonContiguous */ 0);
}
if (!frame) {
@@ -3082,63 +4157,86 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms,
{
const BYTE* ip = (const BYTE*) src;
const BYTE* const iend = ip + srcSize;
+ int const loadLdmDict = params->ldmParams.enableLdm && ls != NULL;
+
+ /* Assert that we the ms params match the params we're being given */
+ ZSTD_assertEqualCParams(params->cParams, ms->cParams);
- ZSTD_window_update(&ms->window, src, srcSize);
+ if (srcSize > ZSTD_CHUNKSIZE_MAX) {
+ /* Allow the dictionary to set indices up to exactly ZSTD_CURRENT_MAX.
+ * Dictionaries right at the edge will immediately trigger overflow
+ * correction, but I don't want to insert extra constraints here.
+ */
+ U32 const maxDictSize = ZSTD_CURRENT_MAX - 1;
+ /* We must have cleared our windows when our source is this large. */
+ assert(ZSTD_window_isEmpty(ms->window));
+ if (loadLdmDict)
+ assert(ZSTD_window_isEmpty(ls->window));
+ /* If the dictionary is too large, only load the suffix of the dictionary. */
+ if (srcSize > maxDictSize) {
+ ip = iend - maxDictSize;
+ src = ip;
+ srcSize = maxDictSize;
+ }
+ }
+
+ DEBUGLOG(4, "ZSTD_loadDictionaryContent(): useRowMatchFinder=%d", (int)params->useRowMatchFinder);
+ ZSTD_window_update(&ms->window, src, srcSize, /* forceNonContiguous */ 0);
ms->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ms->window.base);
+ ms->forceNonContiguous = params->deterministicRefPrefix;
- if (params->ldmParams.enableLdm && ls != NULL) {
- ZSTD_window_update(&ls->window, src, srcSize);
+ if (loadLdmDict) {
+ ZSTD_window_update(&ls->window, src, srcSize, /* forceNonContiguous */ 0);
ls->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ls->window.base);
}
- /* Assert that we the ms params match the params we're being given */
- ZSTD_assertEqualCParams(params->cParams, ms->cParams);
-
if (srcSize <= HASH_READ_SIZE) return 0;
- while (iend - ip > HASH_READ_SIZE) {
- size_t const remaining = (size_t)(iend - ip);
- size_t const chunk = MIN(remaining, ZSTD_CHUNKSIZE_MAX);
- const BYTE* const ichunk = ip + chunk;
+ ZSTD_overflowCorrectIfNeeded(ms, ws, params, ip, iend);
- ZSTD_overflowCorrectIfNeeded(ms, ws, params, ip, ichunk);
+ if (loadLdmDict)
+ ZSTD_ldm_fillHashTable(ls, ip, iend, &params->ldmParams);
- if (params->ldmParams.enableLdm && ls != NULL)
- ZSTD_ldm_fillHashTable(ls, (const BYTE*)src, (const BYTE*)src + srcSize, &params->ldmParams);
-
- switch(params->cParams.strategy)
- {
- case ZSTD_fast:
- ZSTD_fillHashTable(ms, ichunk, dtlm);
- break;
- case ZSTD_dfast:
- ZSTD_fillDoubleHashTable(ms, ichunk, dtlm);
- break;
+ switch(params->cParams.strategy)
+ {
+ case ZSTD_fast:
+ ZSTD_fillHashTable(ms, iend, dtlm);
+ break;
+ case ZSTD_dfast:
+ ZSTD_fillDoubleHashTable(ms, iend, dtlm);
+ break;
- case ZSTD_greedy:
- case ZSTD_lazy:
- case ZSTD_lazy2:
- if (chunk >= HASH_READ_SIZE && ms->dedicatedDictSearch) {
- assert(chunk == remaining); /* must load everything in one go */
- ZSTD_dedicatedDictSearch_lazy_loadDictionary(ms, ichunk-HASH_READ_SIZE);
- } else if (chunk >= HASH_READ_SIZE) {
- ZSTD_insertAndFindFirstIndex(ms, ichunk-HASH_READ_SIZE);
+ case ZSTD_greedy:
+ case ZSTD_lazy:
+ case ZSTD_lazy2:
+ assert(srcSize >= HASH_READ_SIZE);
+ if (ms->dedicatedDictSearch) {
+ assert(ms->chainTable != NULL);
+ ZSTD_dedicatedDictSearch_lazy_loadDictionary(ms, iend-HASH_READ_SIZE);
+ } else {
+ assert(params->useRowMatchFinder != ZSTD_urm_auto);
+ if (params->useRowMatchFinder == ZSTD_urm_enableRowMatchFinder) {
+ size_t const tagTableSize = ((size_t)1 << params->cParams.hashLog) * sizeof(U16);
+ ZSTD_memset(ms->tagTable, 0, tagTableSize);
+ ZSTD_row_update(ms, iend-HASH_READ_SIZE);
+ DEBUGLOG(4, "Using row-based hash table for lazy dict");
+ } else {
+ ZSTD_insertAndFindFirstIndex(ms, iend-HASH_READ_SIZE);
+ DEBUGLOG(4, "Using chain-based hash table for lazy dict");
}
- break;
-
- case ZSTD_btlazy2: /* we want the dictionary table fully sorted */
- case ZSTD_btopt:
- case ZSTD_btultra:
- case ZSTD_btultra2:
- if (chunk >= HASH_READ_SIZE)
- ZSTD_updateTree(ms, ichunk-HASH_READ_SIZE, ichunk);
- break;
-
- default:
- assert(0); /* not possible : not a valid strategy id */
}
+ break;
+
+ case ZSTD_btlazy2: /* we want the dictionary table fully sorted */
+ case ZSTD_btopt:
+ case ZSTD_btultra:
+ case ZSTD_btultra2:
+ assert(srcSize >= HASH_READ_SIZE);
+ ZSTD_updateTree(ms, iend-HASH_READ_SIZE, iend);
+ break;
- ip = ichunk;
+ default:
+ assert(0); /* not possible : not a valid strategy id */
}
ms->nextToUpdate = (U32)(iend - ms->window.base);
@@ -3277,7 +4375,6 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs,
const BYTE* const dictEnd = dictPtr + dictSize;
size_t dictID;
size_t eSize;
-
ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog)));
assert(dictSize >= 8);
assert(MEM_readLE32(dictPtr) == ZSTD_MAGIC_DICTIONARY);
@@ -3348,6 +4445,10 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
const ZSTD_CCtx_params* params, U64 pledgedSrcSize,
ZSTD_buffered_policy_e zbuff)
{
+ size_t const dictContentSize = cdict ? cdict->dictContentSize : dictSize;
+#if ZSTD_TRACE
+ cctx->traceCtx = (ZSTD_trace_compress_begin != NULL) ? ZSTD_trace_compress_begin(cctx) : 0;
+#endif
DEBUGLOG(4, "ZSTD_compressBegin_internal: wlog=%u", params->cParams.windowLog);
/* params are supposed to be fully validated at this point */
assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams)));
@@ -3362,7 +4463,8 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
return ZSTD_resetCCtx_usingCDict(cctx, cdict, params, pledgedSrcSize, zbuff);
}
- FORWARD_IF_ERROR( ZSTD_resetCCtx_internal(cctx, *params, pledgedSrcSize,
+ FORWARD_IF_ERROR( ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
+ dictContentSize,
ZSTDcrp_makeClean, zbuff) , "");
{ size_t const dictID = cdict ?
ZSTD_compress_insertDictionary(
@@ -3377,6 +4479,7 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
FORWARD_IF_ERROR(dictID, "ZSTD_compress_insertDictionary failed");
assert(dictID <= UINT_MAX);
cctx->dictID = (U32)dictID;
+ cctx->dictContentSize = dictContentSize;
}
return 0;
}
@@ -3405,8 +4508,8 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
const void* dict, size_t dictSize,
ZSTD_parameters params, unsigned long long pledgedSrcSize)
{
- ZSTD_CCtx_params const cctxParams =
- ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, &params);
+ ZSTD_CCtx_params cctxParams;
+ ZSTD_CCtxParams_init_internal(&cctxParams, &params, ZSTD_NO_CLEVEL);
return ZSTD_compressBegin_advanced_internal(cctx,
dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast,
NULL /*cdict*/,
@@ -3415,9 +4518,11 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
{
- ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_noAttachDict);
- ZSTD_CCtx_params const cctxParams =
- ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, &params);
+ ZSTD_CCtx_params cctxParams;
+ {
+ ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_noAttachDict);
+ ZSTD_CCtxParams_init_internal(&cctxParams, &params, (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel);
+ }
DEBUGLOG(4, "ZSTD_compressBegin_usingDict (dictSize=%u)", (unsigned)dictSize);
return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL,
&cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, ZSTDb_not_buffered);
@@ -3471,6 +4576,30 @@ static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
return op-ostart;
}
+void ZSTD_CCtx_trace(ZSTD_CCtx* cctx, size_t extraCSize)
+{
+#if ZSTD_TRACE
+ if (cctx->traceCtx && ZSTD_trace_compress_end != NULL) {
+ int const streaming = cctx->inBuffSize > 0 || cctx->outBuffSize > 0 || cctx->appliedParams.nbWorkers > 0;
+ ZSTD_Trace trace;
+ ZSTD_memset(&trace, 0, sizeof(trace));
+ trace.version = ZSTD_VERSION_NUMBER;
+ trace.streaming = streaming;
+ trace.dictionaryID = cctx->dictID;
+ trace.dictionarySize = cctx->dictContentSize;
+ trace.uncompressedSize = cctx->consumedSrcSize;
+ trace.compressedSize = cctx->producedCSize + extraCSize;
+ trace.params = &cctx->appliedParams;
+ trace.cctx = cctx;
+ ZSTD_trace_compress_end(cctx->traceCtx, &trace);
+ }
+ cctx->traceCtx = 0;
+#else
+ (void)cctx;
+ (void)extraCSize;
+#endif
+}
+
size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
void* dst, size_t dstCapacity,
const void* src, size_t srcSize)
@@ -3493,25 +4622,10 @@ size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
(unsigned)cctx->pledgedSrcSizePlusOne-1,
(unsigned)cctx->consumedSrcSize);
}
+ ZSTD_CCtx_trace(cctx, endResult);
return cSize + endResult;
}
-static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- const void* dict,size_t dictSize,
- const ZSTD_parameters* params)
-{
- ZSTD_CCtx_params const cctxParams =
- ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, params);
- DEBUGLOG(4, "ZSTD_compress_internal");
- return ZSTD_compress_advanced_internal(cctx,
- dst, dstCapacity,
- src, srcSize,
- dict, dictSize,
- &cctxParams);
-}
-
size_t ZSTD_compress_advanced (ZSTD_CCtx* cctx,
void* dst, size_t dstCapacity,
const void* src, size_t srcSize,
@@ -3520,11 +4634,12 @@ size_t ZSTD_compress_advanced (ZSTD_CCtx* cctx,
{
DEBUGLOG(4, "ZSTD_compress_advanced");
FORWARD_IF_ERROR(ZSTD_checkCParams(params.cParams), "");
- return ZSTD_compress_internal(cctx,
- dst, dstCapacity,
- src, srcSize,
- dict, dictSize,
- &params);
+ ZSTD_CCtxParams_init_internal(&cctx->simpleApiParams, &params, ZSTD_NO_CLEVEL);
+ return ZSTD_compress_advanced_internal(cctx,
+ dst, dstCapacity,
+ src, srcSize,
+ dict, dictSize,
+ &cctx->simpleApiParams);
}
/* Internal */
@@ -3548,11 +4663,13 @@ size_t ZSTD_compress_usingDict(ZSTD_CCtx* cctx,
const void* dict, size_t dictSize,
int compressionLevel)
{
- ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, srcSize, dict ? dictSize : 0, ZSTD_cpm_noAttachDict);
- ZSTD_CCtx_params cctxParams = ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, &params);
+ {
+ ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, srcSize, dict ? dictSize : 0, ZSTD_cpm_noAttachDict);
+ assert(params.fParams.contentSizeFlag == 1);
+ ZSTD_CCtxParams_init_internal(&cctx->simpleApiParams, &params, (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT: compressionLevel);
+ }
DEBUGLOG(4, "ZSTD_compress_usingDict (srcSize=%u)", (unsigned)srcSize);
- assert(params.fParams.contentSizeFlag == 1);
- return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, &cctxParams);
+ return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, &cctx->simpleApiParams);
}
size_t ZSTD_compressCCtx(ZSTD_CCtx* cctx,
@@ -3596,7 +4713,10 @@ size_t ZSTD_estimateCDictSize_advanced(
DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (unsigned)sizeof(ZSTD_CDict));
return ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict))
+ ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE)
- + ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0)
+ /* enableDedicatedDictSearch == 1 ensures that CDict estimation will not be too small
+ * in case we are using DDS with row-hash. */
+ + ZSTD_sizeof_matchState(&cParams, ZSTD_resolveRowMatchFinderMode(ZSTD_urm_auto, &cParams),
+ /* enableDedicatedDictSearch */ 1, /* forCCtx */ 0)
+ (dictLoadMethod == ZSTD_dlm_byRef ? 0
: ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void *))));
}
@@ -3627,9 +4747,6 @@ static size_t ZSTD_initCDict_internal(
assert(!ZSTD_checkCParams(params.cParams));
cdict->matchState.cParams = params.cParams;
cdict->matchState.dedicatedDictSearch = params.enableDedicatedDictSearch;
- if (cdict->matchState.dedicatedDictSearch && dictSize > ZSTD_CHUNKSIZE_MAX) {
- cdict->matchState.dedicatedDictSearch = 0;
- }
if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) {
cdict->dictContent = dictBuffer;
} else {
@@ -3650,6 +4767,7 @@ static size_t ZSTD_initCDict_internal(
&cdict->matchState,
&cdict->workspace,
&params.cParams,
+ params.useRowMatchFinder,
ZSTDcrp_makeClean,
ZSTDirp_reset,
ZSTD_resetTarget_CDict), "");
@@ -3673,14 +4791,17 @@ static size_t ZSTD_initCDict_internal(
static ZSTD_CDict* ZSTD_createCDict_advanced_internal(size_t dictSize,
ZSTD_dictLoadMethod_e dictLoadMethod,
- ZSTD_compressionParameters cParams, ZSTD_customMem customMem)
+ ZSTD_compressionParameters cParams,
+ ZSTD_useRowMatchFinderMode_e useRowMatchFinder,
+ U32 enableDedicatedDictSearch,
+ ZSTD_customMem customMem)
{
if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL;
{ size_t const workspaceSize =
ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict)) +
ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE) +
- ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0) +
+ ZSTD_sizeof_matchState(&cParams, useRowMatchFinder, enableDedicatedDictSearch, /* forCCtx */ 0) +
(dictLoadMethod == ZSTD_dlm_byRef ? 0
: ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void*))));
void* const workspace = ZSTD_customMalloc(workspaceSize, customMem);
@@ -3698,8 +4819,8 @@ static ZSTD_CDict* ZSTD_createCDict_advanced_internal(size_t dictSize,
assert(cdict != NULL);
ZSTD_cwksp_move(&cdict->workspace, &ws);
cdict->customMem = customMem;
- cdict->compressionLevel = 0; /* signals advanced API usage */
-
+ cdict->compressionLevel = ZSTD_NO_CLEVEL; /* signals advanced API usage */
+ cdict->useRowMatchFinder = useRowMatchFinder;
return cdict;
}
}
@@ -3751,10 +4872,13 @@ ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_advanced2(
&cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict);
}
+ DEBUGLOG(3, "ZSTD_createCDict_advanced2: DDS: %u", cctxParams.enableDedicatedDictSearch);
cctxParams.cParams = cParams;
+ cctxParams.useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(cctxParams.useRowMatchFinder, &cParams);
cdict = ZSTD_createCDict_advanced_internal(dictSize,
dictLoadMethod, cctxParams.cParams,
+ cctxParams.useRowMatchFinder, cctxParams.enableDedicatedDictSearch,
customMem);
if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
@@ -3823,7 +4947,9 @@ const ZSTD_CDict* ZSTD_initStaticCDict(
ZSTD_dictContentType_e dictContentType,
ZSTD_compressionParameters cParams)
{
- size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0);
+ ZSTD_useRowMatchFinderMode_e const useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(ZSTD_urm_auto, &cParams);
+ /* enableDedicatedDictSearch == 1 ensures matchstate is not too small in case this CDict will be used for DDS + row hash */
+ size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, useRowMatchFinder, /* enableDedicatedDictSearch */ 1, /* forCCtx */ 0);
size_t const neededSize = ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict))
+ (dictLoadMethod == ZSTD_dlm_byRef ? 0
: ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void*))))
@@ -3848,6 +4974,8 @@ const ZSTD_CDict* ZSTD_initStaticCDict(
ZSTD_CCtxParams_init(&params, 0);
params.cParams = cParams;
+ params.useRowMatchFinder = useRowMatchFinder;
+ cdict->useRowMatchFinder = useRowMatchFinder;
if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
dict, dictSize,
@@ -3874,62 +5002,88 @@ unsigned ZSTD_getDictID_fromCDict(const ZSTD_CDict* cdict)
return cdict->dictID;
}
-
-/* ZSTD_compressBegin_usingCDict_advanced() :
- * cdict must be != NULL */
-size_t ZSTD_compressBegin_usingCDict_advanced(
+/* ZSTD_compressBegin_usingCDict_internal() :
+ * Implementation of various ZSTD_compressBegin_usingCDict* functions.
+ */
+static size_t ZSTD_compressBegin_usingCDict_internal(
ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict,
ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize)
{
- DEBUGLOG(4, "ZSTD_compressBegin_usingCDict_advanced");
+ ZSTD_CCtx_params cctxParams;
+ DEBUGLOG(4, "ZSTD_compressBegin_usingCDict_internal");
RETURN_ERROR_IF(cdict==NULL, dictionary_wrong, "NULL pointer!");
- { ZSTD_CCtx_params params = cctx->requestedParams;
+ /* Initialize the cctxParams from the cdict */
+ {
+ ZSTD_parameters params;
+ params.fParams = fParams;
params.cParams = ( pledgedSrcSize < ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF
|| pledgedSrcSize < cdict->dictContentSize * ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER
|| pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN
- || cdict->compressionLevel == 0 )
- && (params.attachDictPref != ZSTD_dictForceLoad) ?
+ || cdict->compressionLevel == 0 ) ?
ZSTD_getCParamsFromCDict(cdict)
: ZSTD_getCParams(cdict->compressionLevel,
pledgedSrcSize,
cdict->dictContentSize);
- /* Increase window log to fit the entire dictionary and source if the
- * source size is known. Limit the increase to 19, which is the
- * window log for compression level 1 with the largest source size.
- */
- if (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN) {
- U32 const limitedSrcSize = (U32)MIN(pledgedSrcSize, 1U << 19);
- U32 const limitedSrcLog = limitedSrcSize > 1 ? ZSTD_highbit32(limitedSrcSize - 1) + 1 : 1;
- params.cParams.windowLog = MAX(params.cParams.windowLog, limitedSrcLog);
- }
- params.fParams = fParams;
- return ZSTD_compressBegin_internal(cctx,
- NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast,
- cdict,
- &params, pledgedSrcSize,
- ZSTDb_not_buffered);
+ ZSTD_CCtxParams_init_internal(&cctxParams, &params, cdict->compressionLevel);
+ }
+ /* Increase window log to fit the entire dictionary and source if the
+ * source size is known. Limit the increase to 19, which is the
+ * window log for compression level 1 with the largest source size.
+ */
+ if (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN) {
+ U32 const limitedSrcSize = (U32)MIN(pledgedSrcSize, 1U << 19);
+ U32 const limitedSrcLog = limitedSrcSize > 1 ? ZSTD_highbit32(limitedSrcSize - 1) + 1 : 1;
+ cctxParams.cParams.windowLog = MAX(cctxParams.cParams.windowLog, limitedSrcLog);
}
+ return ZSTD_compressBegin_internal(cctx,
+ NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast,
+ cdict,
+ &cctxParams, pledgedSrcSize,
+ ZSTDb_not_buffered);
+}
+
+
+/* ZSTD_compressBegin_usingCDict_advanced() :
+ * This function is DEPRECATED.
+ * cdict must be != NULL */
+size_t ZSTD_compressBegin_usingCDict_advanced(
+ ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict,
+ ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize)
+{
+ return ZSTD_compressBegin_usingCDict_internal(cctx, cdict, fParams, pledgedSrcSize);
}
/* ZSTD_compressBegin_usingCDict() :
- * pledgedSrcSize=0 means "unknown"
- * if pledgedSrcSize>0, it will enable contentSizeFlag */
+ * cdict must be != NULL */
size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
{
ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
- DEBUGLOG(4, "ZSTD_compressBegin_usingCDict : dictIDFlag == %u", !fParams.noDictIDFlag);
- return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN);
+ return ZSTD_compressBegin_usingCDict_internal(cctx, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN);
}
-size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx,
+/*! ZSTD_compress_usingCDict_internal():
+ * Implementation of various ZSTD_compress_usingCDict* functions.
+ */
+static size_t ZSTD_compress_usingCDict_internal(ZSTD_CCtx* cctx,
void* dst, size_t dstCapacity,
const void* src, size_t srcSize,
const ZSTD_CDict* cdict, ZSTD_frameParameters fParams)
{
- FORWARD_IF_ERROR(ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, srcSize), ""); /* will check if cdict != NULL */
+ FORWARD_IF_ERROR(ZSTD_compressBegin_usingCDict_internal(cctx, cdict, fParams, srcSize), ""); /* will check if cdict != NULL */
return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
}
+/*! ZSTD_compress_usingCDict_advanced():
+ * This function is DEPRECATED.
+ */
+size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx,
+ void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize,
+ const ZSTD_CDict* cdict, ZSTD_frameParameters fParams)
+{
+ return ZSTD_compress_usingCDict_internal(cctx, dst, dstCapacity, src, srcSize, cdict, fParams);
+}
+
/*! ZSTD_compress_usingCDict() :
* Compression using a digested Dictionary.
* Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times.
@@ -3941,7 +5095,7 @@ size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
const ZSTD_CDict* cdict)
{
ZSTD_frameParameters const fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
- return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, fParams);
+ return ZSTD_compress_usingCDict_internal(cctx, dst, dstCapacity, src, srcSize, cdict, fParams);
}
@@ -4071,7 +5225,7 @@ size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , "");
FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) , "");
- zcs->requestedParams = ZSTD_assignParamsToCCtxParams(&zcs->requestedParams, &params);
+ ZSTD_CCtxParams_setZstdParams(&zcs->requestedParams, &params);
FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) , "");
return 0;
}
@@ -4351,8 +5505,13 @@ static size_t ZSTD_CCtx_init_compressStream2(ZSTD_CCtx* cctx,
FORWARD_IF_ERROR( ZSTD_initLocalDict(cctx) , ""); /* Init the local dict if present. */
ZSTD_memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* single usage */
assert(prefixDict.dict==NULL || cctx->cdict==NULL); /* only one can be set */
- if (cctx->cdict)
- params.compressionLevel = cctx->cdict->compressionLevel; /* let cdict take priority in terms of compression level */
+ if (cctx->cdict && !cctx->localDict.cdict) {
+ /* Let the cdict's compression level take priority over the requested params.
+ * But do not take the cdict's compression level if the "cdict" is actually a localDict
+ * generated from ZSTD_initLocalDict().
+ */
+ params.compressionLevel = cctx->cdict->compressionLevel;
+ }
DEBUGLOG(4, "ZSTD_compressStream2 : transparent init stage");
if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = inSize + 1; /* auto-fix pledgedSrcSize */
{
@@ -4371,11 +5530,21 @@ static size_t ZSTD_CCtx_init_compressStream2(ZSTD_CCtx* cctx,
params.ldmParams.enableLdm = 1;
}
+ if (ZSTD_CParams_useBlockSplitter(&params.cParams)) {
+ DEBUGLOG(4, "Block splitter enabled by default (window size >= 128K, strategy >= btopt)");
+ params.splitBlocks = 1;
+ }
+
+ params.useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(params.useRowMatchFinder, &params.cParams);
+
#ifdef ZSTD_MULTITHREAD
if ((cctx->pledgedSrcSizePlusOne-1) <= ZSTDMT_JOBSIZE_MIN) {
params.nbWorkers = 0; /* do not invoke multi-threading when src size is too small */
}
if (params.nbWorkers > 0) {
+#if ZSTD_TRACE
+ cctx->traceCtx = (ZSTD_trace_compress_begin != NULL) ? ZSTD_trace_compress_begin(cctx) : 0;
+#endif
/* mt context creation */
if (cctx->mtctx == NULL) {
DEBUGLOG(4, "ZSTD_compressStream2: creating new mtctx for nbWorkers=%u",
@@ -4389,6 +5558,10 @@ static size_t ZSTD_CCtx_init_compressStream2(ZSTD_CCtx* cctx,
cctx->mtctx,
prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType,
cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) , "");
+ cctx->dictID = cctx->cdict ? cctx->cdict->dictID : 0;
+ cctx->dictContentSize = cctx->cdict ? cctx->cdict->dictContentSize : prefixDict.dictSize;
+ cctx->consumedSrcSize = 0;
+ cctx->producedCSize = 0;
cctx->streamStage = zcss_load;
cctx->appliedParams = params;
} else
@@ -4450,8 +5623,12 @@ size_t ZSTD_compressStream2( ZSTD_CCtx* cctx,
size_t const ipos = input->pos;
size_t const opos = output->pos;
flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp);
+ cctx->consumedSrcSize += (U64)(input->pos - ipos);
+ cctx->producedCSize += (U64)(output->pos - opos);
if ( ZSTD_isError(flushMin)
|| (endOp == ZSTD_e_end && flushMin == 0) ) { /* compression completed */
+ if (flushMin == 0)
+ ZSTD_CCtx_trace(cctx, 0);
ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only);
}
FORWARD_IF_ERROR(flushMin, "ZSTDMT_compressStream_generic failed");
@@ -4834,7 +6011,7 @@ static size_t ZSTD_compressSequences_internal(ZSTD_CCtx* cctx,
continue;
}
- compressedSeqsSize = ZSTD_entropyCompressSequences(&cctx->seqStore,
+ compressedSeqsSize = ZSTD_entropyCompressSeqStore(&cctx->seqStore,
&cctx->blockState.prevCBlock->entropy, &cctx->blockState.nextCBlock->entropy,
&cctx->appliedParams,
op + ZSTD_blockHeaderSize /* Leave space for block header */, dstCapacity - ZSTD_blockHeaderSize,
@@ -4866,7 +6043,7 @@ static size_t ZSTD_compressSequences_internal(ZSTD_CCtx* cctx,
} else {
U32 cBlockHeader;
/* Error checking and repcodes update */
- ZSTD_confirmRepcodesAndEntropyTables(cctx);
+ ZSTD_blockState_confirmRepcodesAndEntropyTables(&cctx->blockState);
if (cctx->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid)
cctx->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check;
@@ -4967,6 +6144,7 @@ size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
#define ZSTD_MAX_CLEVEL 22
int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
int ZSTD_minCLevel(void) { return (int)-ZSTD_TARGETLENGTH_MAX; }
+int ZSTD_defaultCLevel(void) { return ZSTD_CLEVEL_DEFAULT; }
static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
{ /* "default" - for any srcSize > 256 KB */
@@ -5099,7 +6277,10 @@ static ZSTD_compressionParameters ZSTD_dedicatedDictSearch_getCParams(int const
static int ZSTD_dedicatedDictSearch_isSupported(
ZSTD_compressionParameters const* cParams)
{
- return (cParams->strategy >= ZSTD_greedy) && (cParams->strategy <= ZSTD_lazy2);
+ return (cParams->strategy >= ZSTD_greedy)
+ && (cParams->strategy <= ZSTD_lazy2)
+ && (cParams->hashLog > cParams->chainLog)
+ && (cParams->chainLog <= 24);
}
/**
@@ -5117,6 +6298,9 @@ static void ZSTD_dedicatedDictSearch_revertCParams(
case ZSTD_lazy:
case ZSTD_lazy2:
cParams->hashLog -= ZSTD_LAZY_DDSS_BUCKET_LOG;
+ if (cParams->hashLog < ZSTD_HASHLOG_MIN) {
+ cParams->hashLog = ZSTD_HASHLOG_MIN;
+ }
break;
case ZSTD_btlazy2:
case ZSTD_btopt:
@@ -5165,6 +6349,7 @@ static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel,
else row = compressionLevel;
{ ZSTD_compressionParameters cp = ZSTD_defaultCParameters[tableID][row];
+ DEBUGLOG(5, "ZSTD_getCParams_internal selected tableID: %u row: %u strat: %u", tableID, row, (U32)cp.strategy);
/* acceleration factor */
if (compressionLevel < 0) {
int const clampedCompressionLevel = MAX(ZSTD_minCLevel(), compressionLevel);
diff --git a/thirdparty/zstd/compress/zstd_compress_internal.h b/thirdparty/zstd/compress/zstd_compress_internal.h
index c04998b8b1..3b04fd09f6 100644
--- a/thirdparty/zstd/compress/zstd_compress_internal.h
+++ b/thirdparty/zstd/compress/zstd_compress_internal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
@@ -81,6 +81,53 @@ typedef struct {
ZSTD_fseCTables_t fse;
} ZSTD_entropyCTables_t;
+/***********************************************
+* Entropy buffer statistics structs and funcs *
+***********************************************/
+/** ZSTD_hufCTablesMetadata_t :
+ * Stores Literals Block Type for a super-block in hType, and
+ * huffman tree description in hufDesBuffer.
+ * hufDesSize refers to the size of huffman tree description in bytes.
+ * This metadata is populated in ZSTD_buildBlockEntropyStats_literals() */
+typedef struct {
+ symbolEncodingType_e hType;
+ BYTE hufDesBuffer[ZSTD_MAX_HUF_HEADER_SIZE];
+ size_t hufDesSize;
+} ZSTD_hufCTablesMetadata_t;
+
+/** ZSTD_fseCTablesMetadata_t :
+ * Stores symbol compression modes for a super-block in {ll, ol, ml}Type, and
+ * fse tables in fseTablesBuffer.
+ * fseTablesSize refers to the size of fse tables in bytes.
+ * This metadata is populated in ZSTD_buildBlockEntropyStats_sequences() */
+typedef struct {
+ symbolEncodingType_e llType;
+ symbolEncodingType_e ofType;
+ symbolEncodingType_e mlType;
+ BYTE fseTablesBuffer[ZSTD_MAX_FSE_HEADERS_SIZE];
+ size_t fseTablesSize;
+ size_t lastCountSize; /* This is to account for bug in 1.3.4. More detail in ZSTD_entropyCompressSeqStore_internal() */
+} ZSTD_fseCTablesMetadata_t;
+
+typedef struct {
+ ZSTD_hufCTablesMetadata_t hufMetadata;
+ ZSTD_fseCTablesMetadata_t fseMetadata;
+} ZSTD_entropyCTablesMetadata_t;
+
+/** ZSTD_buildBlockEntropyStats() :
+ * Builds entropy for the block.
+ * @return : 0 on success or error code */
+size_t ZSTD_buildBlockEntropyStats(seqStore_t* seqStorePtr,
+ const ZSTD_entropyCTables_t* prevEntropy,
+ ZSTD_entropyCTables_t* nextEntropy,
+ const ZSTD_CCtx_params* cctxParams,
+ ZSTD_entropyCTablesMetadata_t* entropyMetadata,
+ void* workspace, size_t wkspSize);
+
+/*********************************
+* Compression internals structs *
+*********************************/
+
typedef struct {
U32 off; /* Offset code (offset + ZSTD_REP_MOVE) for the match */
U32 len; /* Raw length of match */
@@ -141,14 +188,21 @@ typedef struct {
} ZSTD_compressedBlockState_t;
typedef struct {
- BYTE const* nextSrc; /* next block here to continue on current prefix */
- BYTE const* base; /* All regular indexes relative to this position */
- BYTE const* dictBase; /* extDict indexes relative to this position */
- U32 dictLimit; /* below that point, need extDict */
- U32 lowLimit; /* below that point, no more valid data */
+ BYTE const* nextSrc; /* next block here to continue on current prefix */
+ BYTE const* base; /* All regular indexes relative to this position */
+ BYTE const* dictBase; /* extDict indexes relative to this position */
+ U32 dictLimit; /* below that point, need extDict */
+ U32 lowLimit; /* below that point, no more valid data */
+ U32 nbOverflowCorrections; /* Number of times overflow correction has run since
+ * ZSTD_window_init(). Useful for debugging coredumps
+ * and for ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY.
+ */
} ZSTD_window_t;
typedef struct ZSTD_matchState_t ZSTD_matchState_t;
+
+#define ZSTD_ROW_HASH_CACHE_SIZE 8 /* Size of prefetching hash cache for row-based matchfinder */
+
struct ZSTD_matchState_t {
ZSTD_window_t window; /* State for window round buffer management */
U32 loadedDictEnd; /* index of end of dictionary, within context's referential.
@@ -160,9 +214,17 @@ struct ZSTD_matchState_t {
*/
U32 nextToUpdate; /* index from which to continue table update */
U32 hashLog3; /* dispatch table for matches of len==3 : larger == faster, more memory */
+
+ U32 rowHashLog; /* For row-based matchfinder: Hashlog based on nb of rows in the hashTable.*/
+ U16* tagTable; /* For row-based matchFinder: A row-based table containing the hashes and head index. */
+ U32 hashCache[ZSTD_ROW_HASH_CACHE_SIZE]; /* For row-based matchFinder: a cache of hashes to improve speed */
+
U32* hashTable;
U32* hashTable3;
U32* chainTable;
+
+ U32 forceNonContiguous; /* Non-zero if we should force non-contiguous load for the next window update. */
+
int dedicatedDictSearch; /* Indicates whether this matchState is using the
* dedicated dictionary search structure.
*/
@@ -184,12 +246,21 @@ typedef struct {
} ldmEntry_t;
typedef struct {
+ BYTE const* split;
+ U32 hash;
+ U32 checksum;
+ ldmEntry_t* bucket;
+} ldmMatchCandidate_t;
+
+#define LDM_BATCH_SIZE 64
+
+typedef struct {
ZSTD_window_t window; /* State for the window round buffer management */
ldmEntry_t* hashTable;
U32 loadedDictEnd;
BYTE* bucketOffsets; /* Next position in bucket to insert entry */
- U64 hashPower; /* Used to compute the rolling hash.
- * Depends on ldmParams.minMatchLength */
+ size_t splitIndices[LDM_BATCH_SIZE];
+ ldmMatchCandidate_t matchCandidates[LDM_BATCH_SIZE];
} ldmState_t;
typedef struct {
@@ -246,6 +317,15 @@ struct ZSTD_CCtx_params_s {
ZSTD_sequenceFormat_e blockDelimiters;
int validateSequences;
+ /* Block splitting */
+ int splitBlocks;
+
+ /* Param for deciding whether to use row-based matchfinder */
+ ZSTD_useRowMatchFinderMode_e useRowMatchFinder;
+
+ /* Always load a dictionary in ext-dict mode (not prefix mode)? */
+ int deterministicRefPrefix;
+
/* Internal use, for createCCtxParams() and freeCCtxParams() only */
ZSTD_customMem customMem;
}; /* typedef'd to ZSTD_CCtx_params within "zstd.h" */
@@ -269,7 +349,9 @@ struct ZSTD_CCtx_s {
int bmi2; /* == 1 if the CPU supports BMI2 and 0 otherwise. CPU support is determined dynamically once per context lifetime. */
ZSTD_CCtx_params requestedParams;
ZSTD_CCtx_params appliedParams;
+ ZSTD_CCtx_params simpleApiParams; /* Param storage used by the simple API - not sticky. Must only be used in top-level simple API functions for storage. */
U32 dictID;
+ size_t dictContentSize;
ZSTD_cwksp workspace; /* manages buffer for dynamic allocations */
size_t blockSize;
@@ -321,6 +403,11 @@ struct ZSTD_CCtx_s {
#ifdef ZSTD_MULTITHREAD
ZSTDMT_CCtx* mtctx;
#endif
+
+ /* Tracing */
+#if ZSTD_TRACE
+ ZSTD_TraceCtx traceCtx;
+#endif
};
typedef enum { ZSTD_dtlm_fast, ZSTD_dtlm_full } ZSTD_dictTableLoadMethod_e;
@@ -355,7 +442,7 @@ typedef enum {
typedef size_t (*ZSTD_blockCompressor) (
ZSTD_matchState_t* bs, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
void const* src, size_t srcSize);
-ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode);
+ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_useRowMatchFinderMode_e rowMatchfinderMode, ZSTD_dictMode_e dictMode);
MEM_STATIC U32 ZSTD_LLcode(U32 litLength)
@@ -532,8 +619,8 @@ void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const BYTE* litera
/* literal Length */
if (litLength>0xFFFF) {
- assert(seqStorePtr->longLengthID == 0); /* there can only be a single long length */
- seqStorePtr->longLengthID = 1;
+ assert(seqStorePtr->longLengthType == ZSTD_llt_none); /* there can only be a single long length */
+ seqStorePtr->longLengthType = ZSTD_llt_literalLength;
seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
}
seqStorePtr->sequences[0].litLength = (U16)litLength;
@@ -543,8 +630,8 @@ void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const BYTE* litera
/* match Length */
if (mlBase>0xFFFF) {
- assert(seqStorePtr->longLengthID == 0); /* there can only be a single long length */
- seqStorePtr->longLengthID = 2;
+ assert(seqStorePtr->longLengthType == ZSTD_llt_none); /* there can only be a single long length */
+ seqStorePtr->longLengthType = ZSTD_llt_matchLength;
seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
}
seqStorePtr->sequences[0].matchLength = (U16)mlBase;
@@ -795,6 +882,13 @@ MEM_STATIC void ZSTD_window_clear(ZSTD_window_t* window)
window->dictLimit = end;
}
+MEM_STATIC U32 ZSTD_window_isEmpty(ZSTD_window_t const window)
+{
+ return window.dictLimit == 1 &&
+ window.lowLimit == 1 &&
+ (window.nextSrc - window.base) == 1;
+}
+
/**
* ZSTD_window_hasExtDict():
* Returns non-zero if the window has a non-empty extDict.
@@ -818,15 +912,69 @@ MEM_STATIC ZSTD_dictMode_e ZSTD_matchState_dictMode(const ZSTD_matchState_t *ms)
ZSTD_noDict;
}
+/* Defining this macro to non-zero tells zstd to run the overflow correction
+ * code much more frequently. This is very inefficient, and should only be
+ * used for tests and fuzzers.
+ */
+#ifndef ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY
+# ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+# define ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY 1
+# else
+# define ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY 0
+# endif
+#endif
+
+/**
+ * ZSTD_window_canOverflowCorrect():
+ * Returns non-zero if the indices are large enough for overflow correction
+ * to work correctly without impacting compression ratio.
+ */
+MEM_STATIC U32 ZSTD_window_canOverflowCorrect(ZSTD_window_t const window,
+ U32 cycleLog,
+ U32 maxDist,
+ U32 loadedDictEnd,
+ void const* src)
+{
+ U32 const cycleSize = 1u << cycleLog;
+ U32 const curr = (U32)((BYTE const*)src - window.base);
+ U32 const minIndexToOverflowCorrect = cycleSize + MAX(maxDist, cycleSize);
+
+ /* Adjust the min index to backoff the overflow correction frequency,
+ * so we don't waste too much CPU in overflow correction. If this
+ * computation overflows we don't really care, we just need to make
+ * sure it is at least minIndexToOverflowCorrect.
+ */
+ U32 const adjustment = window.nbOverflowCorrections + 1;
+ U32 const adjustedIndex = MAX(minIndexToOverflowCorrect * adjustment,
+ minIndexToOverflowCorrect);
+ U32 const indexLargeEnough = curr > adjustedIndex;
+
+ /* Only overflow correct early if the dictionary is invalidated already,
+ * so we don't hurt compression ratio.
+ */
+ U32 const dictionaryInvalidated = curr > maxDist + loadedDictEnd;
+
+ return indexLargeEnough && dictionaryInvalidated;
+}
+
/**
* ZSTD_window_needOverflowCorrection():
* Returns non-zero if the indices are getting too large and need overflow
* protection.
*/
MEM_STATIC U32 ZSTD_window_needOverflowCorrection(ZSTD_window_t const window,
+ U32 cycleLog,
+ U32 maxDist,
+ U32 loadedDictEnd,
+ void const* src,
void const* srcEnd)
{
U32 const curr = (U32)((BYTE const*)srcEnd - window.base);
+ if (ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY) {
+ if (ZSTD_window_canOverflowCorrect(window, cycleLog, maxDist, loadedDictEnd, src)) {
+ return 1;
+ }
+ }
return curr > ZSTD_CURRENT_MAX;
}
@@ -838,7 +986,6 @@ MEM_STATIC U32 ZSTD_window_needOverflowCorrection(ZSTD_window_t const window,
*
* The least significant cycleLog bits of the indices must remain the same,
* which may be 0. Every index up to maxDist in the past must be valid.
- * NOTE: (maxDist & cycleMask) must be zero.
*/
MEM_STATIC U32 ZSTD_window_correctOverflow(ZSTD_window_t* window, U32 cycleLog,
U32 maxDist, void const* src)
@@ -862,17 +1009,25 @@ MEM_STATIC U32 ZSTD_window_correctOverflow(ZSTD_window_t* window, U32 cycleLog,
* 3. (cctx->lowLimit + 1<<windowLog) < 1<<32:
* windowLog <= 31 ==> 3<<29 + 1<<windowLog < 7<<29 < 1<<32.
*/
- U32 const cycleMask = (1U << cycleLog) - 1;
+ U32 const cycleSize = 1u << cycleLog;
+ U32 const cycleMask = cycleSize - 1;
U32 const curr = (U32)((BYTE const*)src - window->base);
U32 const currentCycle0 = curr & cycleMask;
/* Exclude zero so that newCurrent - maxDist >= 1. */
- U32 const currentCycle1 = currentCycle0 == 0 ? (1U << cycleLog) : currentCycle0;
- U32 const newCurrent = currentCycle1 + maxDist;
+ U32 const currentCycle1 = currentCycle0 == 0 ? cycleSize : currentCycle0;
+ U32 const newCurrent = currentCycle1 + MAX(maxDist, cycleSize);
U32 const correction = curr - newCurrent;
- assert((maxDist & cycleMask) == 0);
+ /* maxDist must be a power of two so that:
+ * (newCurrent & cycleMask) == (curr & cycleMask)
+ * This is required to not corrupt the chains / binary tree.
+ */
+ assert((maxDist & (maxDist - 1)) == 0);
+ assert((curr & cycleMask) == (newCurrent & cycleMask));
assert(curr > newCurrent);
- /* Loose bound, should be around 1<<29 (see above) */
- assert(correction > 1<<28);
+ if (!ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY) {
+ /* Loose bound, should be around 1<<29 (see above) */
+ assert(correction > 1<<28);
+ }
window->base += correction;
window->dictBase += correction;
@@ -888,6 +1043,8 @@ MEM_STATIC U32 ZSTD_window_correctOverflow(ZSTD_window_t* window, U32 cycleLog,
assert(window->lowLimit <= newCurrent);
assert(window->dictLimit <= newCurrent);
+ ++window->nbOverflowCorrections;
+
DEBUGLOG(4, "Correction of 0x%x bytes to lowLimit=0x%x", correction,
window->lowLimit);
return correction;
@@ -997,6 +1154,7 @@ MEM_STATIC void ZSTD_window_init(ZSTD_window_t* window) {
window->dictLimit = 1; /* start from 1, so that 1st position is valid */
window->lowLimit = 1; /* it ensures first and later CCtx usages compress the same */
window->nextSrc = window->base + 1; /* see issue #1241 */
+ window->nbOverflowCorrections = 0;
}
/**
@@ -1007,7 +1165,8 @@ MEM_STATIC void ZSTD_window_init(ZSTD_window_t* window) {
* Returns non-zero if the segment is contiguous.
*/
MEM_STATIC U32 ZSTD_window_update(ZSTD_window_t* window,
- void const* src, size_t srcSize)
+ void const* src, size_t srcSize,
+ int forceNonContiguous)
{
BYTE const* const ip = (BYTE const*)src;
U32 contiguous = 1;
@@ -1017,7 +1176,7 @@ MEM_STATIC U32 ZSTD_window_update(ZSTD_window_t* window,
assert(window->base != NULL);
assert(window->dictBase != NULL);
/* Check if blocks follow each other */
- if (src != window->nextSrc) {
+ if (src != window->nextSrc || forceNonContiguous) {
/* not contiguous */
size_t const distanceFromBase = (size_t)(window->nextSrc - window->base);
DEBUGLOG(5, "Non contiguous blocks, new segment starts at %u", window->dictLimit);
@@ -1200,4 +1359,9 @@ size_t ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSe
* condition for correct operation : hashLog > 1 */
U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat);
+/** ZSTD_CCtx_trace() :
+ * Trace the end of a compression call.
+ */
+void ZSTD_CCtx_trace(ZSTD_CCtx* cctx, size_t extraCSize);
+
#endif /* ZSTD_COMPRESS_H */
diff --git a/thirdparty/zstd/compress/zstd_compress_literals.c b/thirdparty/zstd/compress/zstd_compress_literals.c
index 6dd1c1447a..008337bb1b 100644
--- a/thirdparty/zstd/compress/zstd_compress_literals.c
+++ b/thirdparty/zstd/compress/zstd_compress_literals.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
@@ -15,7 +15,7 @@
size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
{
- BYTE* const ostart = (BYTE* const)dst;
+ BYTE* const ostart = (BYTE*)dst;
U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
RETURN_ERROR_IF(srcSize + flSize > dstCapacity, dstSize_tooSmall, "");
@@ -42,7 +42,7 @@ size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src,
size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
{
- BYTE* const ostart = (BYTE* const)dst;
+ BYTE* const ostart = (BYTE*)dst;
U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
(void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */
@@ -117,7 +117,7 @@ size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf,
}
}
- if ((cLitSize==0) | (cLitSize >= srcSize - minGain) | ERR_isError(cLitSize)) {
+ if ((cLitSize==0) || (cLitSize >= srcSize - minGain) || ERR_isError(cLitSize)) {
ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
}
diff --git a/thirdparty/zstd/compress/zstd_compress_literals.h b/thirdparty/zstd/compress/zstd_compress_literals.h
index 8b08705743..9904c0cd30 100644
--- a/thirdparty/zstd/compress/zstd_compress_literals.h
+++ b/thirdparty/zstd/compress/zstd_compress_literals.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
diff --git a/thirdparty/zstd/compress/zstd_compress_sequences.c b/thirdparty/zstd/compress/zstd_compress_sequences.c
index be30c08c6b..611eabdcbb 100644
--- a/thirdparty/zstd/compress/zstd_compress_sequences.c
+++ b/thirdparty/zstd/compress/zstd_compress_sequences.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
@@ -85,6 +85,8 @@ static size_t ZSTD_entropyCost(unsigned const* count, unsigned const max, size_t
{
unsigned cost = 0;
unsigned s;
+
+ assert(total > 0);
for (s = 0; s <= max; ++s) {
unsigned norm = (unsigned)((256 * count[s]) / total);
if (count[s] != 0 && norm == 0)
@@ -232,6 +234,11 @@ ZSTD_selectEncodingType(
return set_compressed;
}
+typedef struct {
+ S16 norm[MaxSeq + 1];
+ U32 wksp[FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(MaxSeq, MaxFSELog)];
+} ZSTD_BuildCTableWksp;
+
size_t
ZSTD_buildCTable(void* dst, size_t dstCapacity,
FSE_CTable* nextCTable, U32 FSELog, symbolEncodingType_e type,
@@ -258,7 +265,7 @@ ZSTD_buildCTable(void* dst, size_t dstCapacity,
FORWARD_IF_ERROR(FSE_buildCTable_wksp(nextCTable, defaultNorm, defaultMax, defaultNormLog, entropyWorkspace, entropyWorkspaceSize), ""); /* note : could be pre-calculated */
return 0;
case set_compressed: {
- S16 norm[MaxSeq + 1];
+ ZSTD_BuildCTableWksp* wksp = (ZSTD_BuildCTableWksp*)entropyWorkspace;
size_t nbSeq_1 = nbSeq;
const U32 tableLog = FSE_optimalTableLog(FSELog, nbSeq, max);
if (count[codeTable[nbSeq-1]] > 1) {
@@ -266,11 +273,12 @@ ZSTD_buildCTable(void* dst, size_t dstCapacity,
nbSeq_1--;
}
assert(nbSeq_1 > 1);
- assert(entropyWorkspaceSize >= FSE_BUILD_CTABLE_WORKSPACE_SIZE(MaxSeq, MaxFSELog));
- FORWARD_IF_ERROR(FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max, ZSTD_useLowProbCount(nbSeq_1)), "");
- { size_t const NCountSize = FSE_writeNCount(op, oend - op, norm, max, tableLog); /* overflow protected */
+ assert(entropyWorkspaceSize >= sizeof(ZSTD_BuildCTableWksp));
+ (void)entropyWorkspaceSize;
+ FORWARD_IF_ERROR(FSE_normalizeCount(wksp->norm, tableLog, count, nbSeq_1, max, ZSTD_useLowProbCount(nbSeq_1)), "");
+ { size_t const NCountSize = FSE_writeNCount(op, oend - op, wksp->norm, max, tableLog); /* overflow protected */
FORWARD_IF_ERROR(NCountSize, "FSE_writeNCount failed");
- FORWARD_IF_ERROR(FSE_buildCTable_wksp(nextCTable, norm, max, tableLog, entropyWorkspace, entropyWorkspaceSize), "");
+ FORWARD_IF_ERROR(FSE_buildCTable_wksp(nextCTable, wksp->norm, max, tableLog, wksp->wksp, sizeof(wksp->wksp)), "");
return NCountSize;
}
}
diff --git a/thirdparty/zstd/compress/zstd_compress_sequences.h b/thirdparty/zstd/compress/zstd_compress_sequences.h
index 68c6f9a5ac..7991364c2f 100644
--- a/thirdparty/zstd/compress/zstd_compress_sequences.h
+++ b/thirdparty/zstd/compress/zstd_compress_sequences.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
diff --git a/thirdparty/zstd/compress/zstd_compress_superblock.c b/thirdparty/zstd/compress/zstd_compress_superblock.c
index e23e619eef..e4e45069bc 100644
--- a/thirdparty/zstd/compress/zstd_compress_superblock.c
+++ b/thirdparty/zstd/compress/zstd_compress_superblock.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
@@ -15,288 +15,10 @@
#include "../common/zstd_internal.h" /* ZSTD_getSequenceLength */
#include "hist.h" /* HIST_countFast_wksp */
-#include "zstd_compress_internal.h"
+#include "zstd_compress_internal.h" /* ZSTD_[huf|fse|entropy]CTablesMetadata_t */
#include "zstd_compress_sequences.h"
#include "zstd_compress_literals.h"
-/*-*************************************
-* Superblock entropy buffer structs
-***************************************/
-/** ZSTD_hufCTablesMetadata_t :
- * Stores Literals Block Type for a super-block in hType, and
- * huffman tree description in hufDesBuffer.
- * hufDesSize refers to the size of huffman tree description in bytes.
- * This metadata is populated in ZSTD_buildSuperBlockEntropy_literal() */
-typedef struct {
- symbolEncodingType_e hType;
- BYTE hufDesBuffer[ZSTD_MAX_HUF_HEADER_SIZE];
- size_t hufDesSize;
-} ZSTD_hufCTablesMetadata_t;
-
-/** ZSTD_fseCTablesMetadata_t :
- * Stores symbol compression modes for a super-block in {ll, ol, ml}Type, and
- * fse tables in fseTablesBuffer.
- * fseTablesSize refers to the size of fse tables in bytes.
- * This metadata is populated in ZSTD_buildSuperBlockEntropy_sequences() */
-typedef struct {
- symbolEncodingType_e llType;
- symbolEncodingType_e ofType;
- symbolEncodingType_e mlType;
- BYTE fseTablesBuffer[ZSTD_MAX_FSE_HEADERS_SIZE];
- size_t fseTablesSize;
- size_t lastCountSize; /* This is to account for bug in 1.3.4. More detail in ZSTD_compressSubBlock_sequences() */
-} ZSTD_fseCTablesMetadata_t;
-
-typedef struct {
- ZSTD_hufCTablesMetadata_t hufMetadata;
- ZSTD_fseCTablesMetadata_t fseMetadata;
-} ZSTD_entropyCTablesMetadata_t;
-
-
-/** ZSTD_buildSuperBlockEntropy_literal() :
- * Builds entropy for the super-block literals.
- * Stores literals block type (raw, rle, compressed, repeat) and
- * huffman description table to hufMetadata.
- * @return : size of huffman description table or error code */
-static size_t ZSTD_buildSuperBlockEntropy_literal(void* const src, size_t srcSize,
- const ZSTD_hufCTables_t* prevHuf,
- ZSTD_hufCTables_t* nextHuf,
- ZSTD_hufCTablesMetadata_t* hufMetadata,
- const int disableLiteralsCompression,
- void* workspace, size_t wkspSize)
-{
- BYTE* const wkspStart = (BYTE*)workspace;
- BYTE* const wkspEnd = wkspStart + wkspSize;
- BYTE* const countWkspStart = wkspStart;
- unsigned* const countWksp = (unsigned*)workspace;
- const size_t countWkspSize = (HUF_SYMBOLVALUE_MAX + 1) * sizeof(unsigned);
- BYTE* const nodeWksp = countWkspStart + countWkspSize;
- const size_t nodeWkspSize = wkspEnd-nodeWksp;
- unsigned maxSymbolValue = 255;
- unsigned huffLog = HUF_TABLELOG_DEFAULT;
- HUF_repeat repeat = prevHuf->repeatMode;
-
- DEBUGLOG(5, "ZSTD_buildSuperBlockEntropy_literal (srcSize=%zu)", srcSize);
-
- /* Prepare nextEntropy assuming reusing the existing table */
- ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
-
- if (disableLiteralsCompression) {
- DEBUGLOG(5, "set_basic - disabled");
- hufMetadata->hType = set_basic;
- return 0;
- }
-
- /* small ? don't even attempt compression (speed opt) */
-# define COMPRESS_LITERALS_SIZE_MIN 63
- { size_t const minLitSize = (prevHuf->repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN;
- if (srcSize <= minLitSize) {
- DEBUGLOG(5, "set_basic - too small");
- hufMetadata->hType = set_basic;
- return 0;
- }
- }
-
- /* Scan input and build symbol stats */
- { size_t const largest = HIST_count_wksp (countWksp, &maxSymbolValue, (const BYTE*)src, srcSize, workspace, wkspSize);
- FORWARD_IF_ERROR(largest, "HIST_count_wksp failed");
- if (largest == srcSize) {
- DEBUGLOG(5, "set_rle");
- hufMetadata->hType = set_rle;
- return 0;
- }
- if (largest <= (srcSize >> 7)+4) {
- DEBUGLOG(5, "set_basic - no gain");
- hufMetadata->hType = set_basic;
- return 0;
- }
- }
-
- /* Validate the previous Huffman table */
- if (repeat == HUF_repeat_check && !HUF_validateCTable((HUF_CElt const*)prevHuf->CTable, countWksp, maxSymbolValue)) {
- repeat = HUF_repeat_none;
- }
-
- /* Build Huffman Tree */
- ZSTD_memset(nextHuf->CTable, 0, sizeof(nextHuf->CTable));
- huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue);
- { size_t const maxBits = HUF_buildCTable_wksp((HUF_CElt*)nextHuf->CTable, countWksp,
- maxSymbolValue, huffLog,
- nodeWksp, nodeWkspSize);
- FORWARD_IF_ERROR(maxBits, "HUF_buildCTable_wksp");
- huffLog = (U32)maxBits;
- { /* Build and write the CTable */
- size_t const newCSize = HUF_estimateCompressedSize(
- (HUF_CElt*)nextHuf->CTable, countWksp, maxSymbolValue);
- size_t const hSize = HUF_writeCTable(
- hufMetadata->hufDesBuffer, sizeof(hufMetadata->hufDesBuffer),
- (HUF_CElt*)nextHuf->CTable, maxSymbolValue, huffLog);
- /* Check against repeating the previous CTable */
- if (repeat != HUF_repeat_none) {
- size_t const oldCSize = HUF_estimateCompressedSize(
- (HUF_CElt const*)prevHuf->CTable, countWksp, maxSymbolValue);
- if (oldCSize < srcSize && (oldCSize <= hSize + newCSize || hSize + 12 >= srcSize)) {
- DEBUGLOG(5, "set_repeat - smaller");
- ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
- hufMetadata->hType = set_repeat;
- return 0;
- }
- }
- if (newCSize + hSize >= srcSize) {
- DEBUGLOG(5, "set_basic - no gains");
- ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
- hufMetadata->hType = set_basic;
- return 0;
- }
- DEBUGLOG(5, "set_compressed (hSize=%u)", (U32)hSize);
- hufMetadata->hType = set_compressed;
- nextHuf->repeatMode = HUF_repeat_check;
- return hSize;
- }
- }
-}
-
-/** ZSTD_buildSuperBlockEntropy_sequences() :
- * Builds entropy for the super-block sequences.
- * Stores symbol compression modes and fse table to fseMetadata.
- * @return : size of fse tables or error code */
-static size_t ZSTD_buildSuperBlockEntropy_sequences(seqStore_t* seqStorePtr,
- const ZSTD_fseCTables_t* prevEntropy,
- ZSTD_fseCTables_t* nextEntropy,
- const ZSTD_CCtx_params* cctxParams,
- ZSTD_fseCTablesMetadata_t* fseMetadata,
- void* workspace, size_t wkspSize)
-{
- BYTE* const wkspStart = (BYTE*)workspace;
- BYTE* const wkspEnd = wkspStart + wkspSize;
- BYTE* const countWkspStart = wkspStart;
- unsigned* const countWksp = (unsigned*)workspace;
- const size_t countWkspSize = (MaxSeq + 1) * sizeof(unsigned);
- BYTE* const cTableWksp = countWkspStart + countWkspSize;
- const size_t cTableWkspSize = wkspEnd-cTableWksp;
- ZSTD_strategy const strategy = cctxParams->cParams.strategy;
- FSE_CTable* CTable_LitLength = nextEntropy->litlengthCTable;
- FSE_CTable* CTable_OffsetBits = nextEntropy->offcodeCTable;
- FSE_CTable* CTable_MatchLength = nextEntropy->matchlengthCTable;
- const BYTE* const ofCodeTable = seqStorePtr->ofCode;
- const BYTE* const llCodeTable = seqStorePtr->llCode;
- const BYTE* const mlCodeTable = seqStorePtr->mlCode;
- size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
- BYTE* const ostart = fseMetadata->fseTablesBuffer;
- BYTE* const oend = ostart + sizeof(fseMetadata->fseTablesBuffer);
- BYTE* op = ostart;
-
- assert(cTableWkspSize >= (1 << MaxFSELog) * sizeof(FSE_FUNCTION_TYPE));
- DEBUGLOG(5, "ZSTD_buildSuperBlockEntropy_sequences (nbSeq=%zu)", nbSeq);
- ZSTD_memset(workspace, 0, wkspSize);
-
- fseMetadata->lastCountSize = 0;
- /* convert length/distances into codes */
- ZSTD_seqToCodes(seqStorePtr);
- /* build CTable for Literal Lengths */
- { U32 LLtype;
- unsigned max = MaxLL;
- size_t const mostFrequent = HIST_countFast_wksp(countWksp, &max, llCodeTable, nbSeq, workspace, wkspSize); /* can't fail */
- DEBUGLOG(5, "Building LL table");
- nextEntropy->litlength_repeatMode = prevEntropy->litlength_repeatMode;
- LLtype = ZSTD_selectEncodingType(&nextEntropy->litlength_repeatMode,
- countWksp, max, mostFrequent, nbSeq,
- LLFSELog, prevEntropy->litlengthCTable,
- LL_defaultNorm, LL_defaultNormLog,
- ZSTD_defaultAllowed, strategy);
- assert(set_basic < set_compressed && set_rle < set_compressed);
- assert(!(LLtype < set_compressed && nextEntropy->litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
- { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype,
- countWksp, max, llCodeTable, nbSeq, LL_defaultNorm, LL_defaultNormLog, MaxLL,
- prevEntropy->litlengthCTable, sizeof(prevEntropy->litlengthCTable),
- cTableWksp, cTableWkspSize);
- FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for LitLens failed");
- if (LLtype == set_compressed)
- fseMetadata->lastCountSize = countSize;
- op += countSize;
- fseMetadata->llType = (symbolEncodingType_e) LLtype;
- } }
- /* build CTable for Offsets */
- { U32 Offtype;
- unsigned max = MaxOff;
- size_t const mostFrequent = HIST_countFast_wksp(countWksp, &max, ofCodeTable, nbSeq, workspace, wkspSize); /* can't fail */
- /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */
- ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed;
- DEBUGLOG(5, "Building OF table");
- nextEntropy->offcode_repeatMode = prevEntropy->offcode_repeatMode;
- Offtype = ZSTD_selectEncodingType(&nextEntropy->offcode_repeatMode,
- countWksp, max, mostFrequent, nbSeq,
- OffFSELog, prevEntropy->offcodeCTable,
- OF_defaultNorm, OF_defaultNormLog,
- defaultPolicy, strategy);
- assert(!(Offtype < set_compressed && nextEntropy->offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */
- { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype,
- countWksp, max, ofCodeTable, nbSeq, OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
- prevEntropy->offcodeCTable, sizeof(prevEntropy->offcodeCTable),
- cTableWksp, cTableWkspSize);
- FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for Offsets failed");
- if (Offtype == set_compressed)
- fseMetadata->lastCountSize = countSize;
- op += countSize;
- fseMetadata->ofType = (symbolEncodingType_e) Offtype;
- } }
- /* build CTable for MatchLengths */
- { U32 MLtype;
- unsigned max = MaxML;
- size_t const mostFrequent = HIST_countFast_wksp(countWksp, &max, mlCodeTable, nbSeq, workspace, wkspSize); /* can't fail */
- DEBUGLOG(5, "Building ML table (remaining space : %i)", (int)(oend-op));
- nextEntropy->matchlength_repeatMode = prevEntropy->matchlength_repeatMode;
- MLtype = ZSTD_selectEncodingType(&nextEntropy->matchlength_repeatMode,
- countWksp, max, mostFrequent, nbSeq,
- MLFSELog, prevEntropy->matchlengthCTable,
- ML_defaultNorm, ML_defaultNormLog,
- ZSTD_defaultAllowed, strategy);
- assert(!(MLtype < set_compressed && nextEntropy->matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
- { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype,
- countWksp, max, mlCodeTable, nbSeq, ML_defaultNorm, ML_defaultNormLog, MaxML,
- prevEntropy->matchlengthCTable, sizeof(prevEntropy->matchlengthCTable),
- cTableWksp, cTableWkspSize);
- FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for MatchLengths failed");
- if (MLtype == set_compressed)
- fseMetadata->lastCountSize = countSize;
- op += countSize;
- fseMetadata->mlType = (symbolEncodingType_e) MLtype;
- } }
- assert((size_t) (op-ostart) <= sizeof(fseMetadata->fseTablesBuffer));
- return op-ostart;
-}
-
-
-/** ZSTD_buildSuperBlockEntropy() :
- * Builds entropy for the super-block.
- * @return : 0 on success or error code */
-static size_t
-ZSTD_buildSuperBlockEntropy(seqStore_t* seqStorePtr,
- const ZSTD_entropyCTables_t* prevEntropy,
- ZSTD_entropyCTables_t* nextEntropy,
- const ZSTD_CCtx_params* cctxParams,
- ZSTD_entropyCTablesMetadata_t* entropyMetadata,
- void* workspace, size_t wkspSize)
-{
- size_t const litSize = seqStorePtr->lit - seqStorePtr->litStart;
- DEBUGLOG(5, "ZSTD_buildSuperBlockEntropy");
- entropyMetadata->hufMetadata.hufDesSize =
- ZSTD_buildSuperBlockEntropy_literal(seqStorePtr->litStart, litSize,
- &prevEntropy->huf, &nextEntropy->huf,
- &entropyMetadata->hufMetadata,
- ZSTD_disableLiteralsCompression(cctxParams),
- workspace, wkspSize);
- FORWARD_IF_ERROR(entropyMetadata->hufMetadata.hufDesSize, "ZSTD_buildSuperBlockEntropy_literal failed");
- entropyMetadata->fseMetadata.fseTablesSize =
- ZSTD_buildSuperBlockEntropy_sequences(seqStorePtr,
- &prevEntropy->fse, &nextEntropy->fse,
- cctxParams,
- &entropyMetadata->fseMetadata,
- workspace, wkspSize);
- FORWARD_IF_ERROR(entropyMetadata->fseMetadata.fseTablesSize, "ZSTD_buildSuperBlockEntropy_sequences failed");
- return 0;
-}
-
/** ZSTD_compressSubBlock_literal() :
* Compresses literals section for a sub-block.
* When we have to write the Huffman table we will sometimes choose a header
@@ -304,7 +26,7 @@ ZSTD_buildSuperBlockEntropy(seqStore_t* seqStorePtr,
* before we know the table size + compressed size, so we have a bound on the
* table size. If we guessed incorrectly, we fall back to uncompressed literals.
*
- * We write the header when writeEntropy=1 and set entropyWrriten=1 when we succeeded
+ * We write the header when writeEntropy=1 and set entropyWritten=1 when we succeeded
* in writing the header, otherwise it is set to 0.
*
* hufMetadata->hType has literals block type info.
@@ -643,8 +365,9 @@ static size_t ZSTD_estimateSubBlockSize_sequences(const BYTE* ofCodeTable,
void* workspace, size_t wkspSize,
int writeEntropy)
{
- size_t sequencesSectionHeaderSize = 3; /* Use hard coded size of 3 bytes */
+ size_t const sequencesSectionHeaderSize = 3; /* Use hard coded size of 3 bytes */
size_t cSeqSizeEstimate = 0;
+ if (nbSeq == 0) return sequencesSectionHeaderSize;
cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->ofType, ofCodeTable, MaxOff,
nbSeq, fseTables->offcodeCTable, NULL,
OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
@@ -830,7 +553,7 @@ size_t ZSTD_compressSuperBlock(ZSTD_CCtx* zc,
unsigned lastBlock) {
ZSTD_entropyCTablesMetadata_t entropyMetadata;
- FORWARD_IF_ERROR(ZSTD_buildSuperBlockEntropy(&zc->seqStore,
+ FORWARD_IF_ERROR(ZSTD_buildBlockEntropyStats(&zc->seqStore,
&zc->blockState.prevCBlock->entropy,
&zc->blockState.nextCBlock->entropy,
&zc->appliedParams,
diff --git a/thirdparty/zstd/compress/zstd_compress_superblock.h b/thirdparty/zstd/compress/zstd_compress_superblock.h
index 07f4cb1dc6..176f9b106f 100644
--- a/thirdparty/zstd/compress/zstd_compress_superblock.h
+++ b/thirdparty/zstd/compress/zstd_compress_superblock.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
diff --git a/thirdparty/zstd/compress/zstd_cwksp.h b/thirdparty/zstd/compress/zstd_cwksp.h
index d65170b39c..2656d26ca2 100644
--- a/thirdparty/zstd/compress/zstd_cwksp.h
+++ b/thirdparty/zstd/compress/zstd_cwksp.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
@@ -35,6 +35,10 @@ extern "C" {
#define ZSTD_CWKSP_ASAN_REDZONE_SIZE 128
#endif
+
+/* Set our tables and aligneds to align by 64 bytes */
+#define ZSTD_CWKSP_ALIGNMENT_BYTES 64
+
/*-*************************************
* Structures
***************************************/
@@ -117,10 +121,11 @@ typedef enum {
* - Tables: these are any of several different datastructures (hash tables,
* chain tables, binary trees) that all respect a common format: they are
* uint32_t arrays, all of whose values are between 0 and (nextSrc - base).
- * Their sizes depend on the cparams.
+ * Their sizes depend on the cparams. These tables are 64-byte aligned.
*
* - Aligned: these buffers are used for various purposes that require 4 byte
- * alignment, but don't require any initialization before they're used.
+ * alignment, but don't require any initialization before they're used. These
+ * buffers are each aligned to 64 bytes.
*
* - Buffers: these buffers are used for various purposes that don't require
* any alignment or initialization before they're used. This means they can
@@ -133,8 +138,7 @@ typedef enum {
*
* 1. Objects
* 2. Buffers
- * 3. Aligned
- * 4. Tables
+ * 3. Aligned/Tables
*
* Attempts to reserve objects of different types out of order will fail.
*/
@@ -187,6 +191,8 @@ MEM_STATIC size_t ZSTD_cwksp_align(size_t size, size_t const align) {
* Since tables aren't currently redzoned, you don't need to call through this
* to figure out how much space you need for the matchState tables. Everything
* else is though.
+ *
+ * Do not use for sizing aligned buffers. Instead, use ZSTD_cwksp_aligned_alloc_size().
*/
MEM_STATIC size_t ZSTD_cwksp_alloc_size(size_t size) {
if (size == 0)
@@ -198,30 +204,110 @@ MEM_STATIC size_t ZSTD_cwksp_alloc_size(size_t size) {
#endif
}
-MEM_STATIC void ZSTD_cwksp_internal_advance_phase(
+/**
+ * Returns an adjusted alloc size that is the nearest larger multiple of 64 bytes.
+ * Used to determine the number of bytes required for a given "aligned".
+ */
+MEM_STATIC size_t ZSTD_cwksp_aligned_alloc_size(size_t size) {
+ return ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(size, ZSTD_CWKSP_ALIGNMENT_BYTES));
+}
+
+/**
+ * Returns the amount of additional space the cwksp must allocate
+ * for internal purposes (currently only alignment).
+ */
+MEM_STATIC size_t ZSTD_cwksp_slack_space_required(void) {
+ /* For alignment, the wksp will always allocate an additional n_1=[1, 64] bytes
+ * to align the beginning of tables section, as well as another n_2=[0, 63] bytes
+ * to align the beginning of the aligned secion.
+ *
+ * n_1 + n_2 == 64 bytes if the cwksp is freshly allocated, due to tables and
+ * aligneds being sized in multiples of 64 bytes.
+ */
+ size_t const slackSpace = ZSTD_CWKSP_ALIGNMENT_BYTES;
+ return slackSpace;
+}
+
+
+/**
+ * Return the number of additional bytes required to align a pointer to the given number of bytes.
+ * alignBytes must be a power of two.
+ */
+MEM_STATIC size_t ZSTD_cwksp_bytes_to_align_ptr(void* ptr, const size_t alignBytes) {
+ size_t const alignBytesMask = alignBytes - 1;
+ size_t const bytes = (alignBytes - ((size_t)ptr & (alignBytesMask))) & alignBytesMask;
+ assert((alignBytes & alignBytesMask) == 0);
+ assert(bytes != ZSTD_CWKSP_ALIGNMENT_BYTES);
+ return bytes;
+}
+
+/**
+ * Internal function. Do not use directly.
+ * Reserves the given number of bytes within the aligned/buffer segment of the wksp, which
+ * counts from the end of the wksp. (as opposed to the object/table segment)
+ *
+ * Returns a pointer to the beginning of that space.
+ */
+MEM_STATIC void* ZSTD_cwksp_reserve_internal_buffer_space(ZSTD_cwksp* ws, size_t const bytes) {
+ void* const alloc = (BYTE*)ws->allocStart - bytes;
+ void* const bottom = ws->tableEnd;
+ DEBUGLOG(5, "cwksp: reserving %p %zd bytes, %zd bytes remaining",
+ alloc, bytes, ZSTD_cwksp_available_space(ws) - bytes);
+ ZSTD_cwksp_assert_internal_consistency(ws);
+ assert(alloc >= bottom);
+ if (alloc < bottom) {
+ DEBUGLOG(4, "cwksp: alloc failed!");
+ ws->allocFailed = 1;
+ return NULL;
+ }
+ if (alloc < ws->tableValidEnd) {
+ ws->tableValidEnd = alloc;
+ }
+ ws->allocStart = alloc;
+ return alloc;
+}
+
+/**
+ * Moves the cwksp to the next phase, and does any necessary allocations.
+ * Returns a 0 on success, or zstd error
+ */
+MEM_STATIC size_t ZSTD_cwksp_internal_advance_phase(
ZSTD_cwksp* ws, ZSTD_cwksp_alloc_phase_e phase) {
assert(phase >= ws->phase);
if (phase > ws->phase) {
+ /* Going from allocating objects to allocating buffers */
if (ws->phase < ZSTD_cwksp_alloc_buffers &&
phase >= ZSTD_cwksp_alloc_buffers) {
ws->tableValidEnd = ws->objectEnd;
}
+
+ /* Going from allocating buffers to allocating aligneds/tables */
if (ws->phase < ZSTD_cwksp_alloc_aligned &&
phase >= ZSTD_cwksp_alloc_aligned) {
- /* If unaligned allocations down from a too-large top have left us
- * unaligned, we need to realign our alloc ptr. Technically, this
- * can consume space that is unaccounted for in the neededSpace
- * calculation. However, I believe this can only happen when the
- * workspace is too large, and specifically when it is too large
- * by a larger margin than the space that will be consumed. */
- /* TODO: cleaner, compiler warning friendly way to do this??? */
- ws->allocStart = (BYTE*)ws->allocStart - ((size_t)ws->allocStart & (sizeof(U32)-1));
- if (ws->allocStart < ws->tableValidEnd) {
- ws->tableValidEnd = ws->allocStart;
+ { /* Align the start of the "aligned" to 64 bytes. Use [1, 64] bytes. */
+ size_t const bytesToAlign =
+ ZSTD_CWKSP_ALIGNMENT_BYTES - ZSTD_cwksp_bytes_to_align_ptr(ws->allocStart, ZSTD_CWKSP_ALIGNMENT_BYTES);
+ DEBUGLOG(5, "reserving aligned alignment addtl space: %zu", bytesToAlign);
+ ZSTD_STATIC_ASSERT((ZSTD_CWKSP_ALIGNMENT_BYTES & (ZSTD_CWKSP_ALIGNMENT_BYTES - 1)) == 0); /* power of 2 */
+ RETURN_ERROR_IF(!ZSTD_cwksp_reserve_internal_buffer_space(ws, bytesToAlign),
+ memory_allocation, "aligned phase - alignment initial allocation failed!");
+ }
+ { /* Align the start of the tables to 64 bytes. Use [0, 63] bytes */
+ void* const alloc = ws->objectEnd;
+ size_t const bytesToAlign = ZSTD_cwksp_bytes_to_align_ptr(alloc, ZSTD_CWKSP_ALIGNMENT_BYTES);
+ void* const end = (BYTE*)alloc + bytesToAlign;
+ DEBUGLOG(5, "reserving table alignment addtl space: %zu", bytesToAlign);
+ RETURN_ERROR_IF(end > ws->workspaceEnd, memory_allocation,
+ "table phase - alignment initial allocation failed!");
+ ws->objectEnd = end;
+ ws->tableEnd = end;
+ ws->tableValidEnd = end;
}
}
ws->phase = phase;
+ ZSTD_cwksp_assert_internal_consistency(ws);
}
+ return 0;
}
/**
@@ -237,38 +323,25 @@ MEM_STATIC int ZSTD_cwksp_owns_buffer(const ZSTD_cwksp* ws, const void* ptr) {
MEM_STATIC void* ZSTD_cwksp_reserve_internal(
ZSTD_cwksp* ws, size_t bytes, ZSTD_cwksp_alloc_phase_e phase) {
void* alloc;
- void* bottom = ws->tableEnd;
- ZSTD_cwksp_internal_advance_phase(ws, phase);
- alloc = (BYTE *)ws->allocStart - bytes;
-
- if (bytes == 0)
+ if (ZSTD_isError(ZSTD_cwksp_internal_advance_phase(ws, phase)) || bytes == 0) {
return NULL;
+ }
#if ZSTD_ADDRESS_SANITIZER && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
/* over-reserve space */
- alloc = (BYTE *)alloc - 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE;
+ bytes += 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE;
#endif
- DEBUGLOG(5, "cwksp: reserving %p %zd bytes, %zd bytes remaining",
- alloc, bytes, ZSTD_cwksp_available_space(ws) - bytes);
- ZSTD_cwksp_assert_internal_consistency(ws);
- assert(alloc >= bottom);
- if (alloc < bottom) {
- DEBUGLOG(4, "cwksp: alloc failed!");
- ws->allocFailed = 1;
- return NULL;
- }
- if (alloc < ws->tableValidEnd) {
- ws->tableValidEnd = alloc;
- }
- ws->allocStart = alloc;
+ alloc = ZSTD_cwksp_reserve_internal_buffer_space(ws, bytes);
#if ZSTD_ADDRESS_SANITIZER && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
/* Move alloc so there's ZSTD_CWKSP_ASAN_REDZONE_SIZE unused space on
* either size. */
- alloc = (BYTE *)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE;
- if (ws->isStatic == ZSTD_cwksp_dynamic_alloc) {
- __asan_unpoison_memory_region(alloc, bytes);
+ if (alloc) {
+ alloc = (BYTE *)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE;
+ if (ws->isStatic == ZSTD_cwksp_dynamic_alloc) {
+ __asan_unpoison_memory_region(alloc, bytes);
+ }
}
#endif
@@ -283,28 +356,36 @@ MEM_STATIC BYTE* ZSTD_cwksp_reserve_buffer(ZSTD_cwksp* ws, size_t bytes) {
}
/**
- * Reserves and returns memory sized on and aligned on sizeof(unsigned).
+ * Reserves and returns memory sized on and aligned on ZSTD_CWKSP_ALIGNMENT_BYTES (64 bytes).
*/
MEM_STATIC void* ZSTD_cwksp_reserve_aligned(ZSTD_cwksp* ws, size_t bytes) {
- assert((bytes & (sizeof(U32)-1)) == 0);
- return ZSTD_cwksp_reserve_internal(ws, ZSTD_cwksp_align(bytes, sizeof(U32)), ZSTD_cwksp_alloc_aligned);
+ void* ptr = ZSTD_cwksp_reserve_internal(ws, ZSTD_cwksp_align(bytes, ZSTD_CWKSP_ALIGNMENT_BYTES),
+ ZSTD_cwksp_alloc_aligned);
+ assert(((size_t)ptr & (ZSTD_CWKSP_ALIGNMENT_BYTES-1))== 0);
+ return ptr;
}
/**
- * Aligned on sizeof(unsigned). These buffers have the special property that
+ * Aligned on 64 bytes. These buffers have the special property that
* their values remain constrained, allowing us to re-use them without
* memset()-ing them.
*/
MEM_STATIC void* ZSTD_cwksp_reserve_table(ZSTD_cwksp* ws, size_t bytes) {
const ZSTD_cwksp_alloc_phase_e phase = ZSTD_cwksp_alloc_aligned;
- void* alloc = ws->tableEnd;
- void* end = (BYTE *)alloc + bytes;
- void* top = ws->allocStart;
+ void* alloc;
+ void* end;
+ void* top;
+
+ if (ZSTD_isError(ZSTD_cwksp_internal_advance_phase(ws, phase))) {
+ return NULL;
+ }
+ alloc = ws->tableEnd;
+ end = (BYTE *)alloc + bytes;
+ top = ws->allocStart;
DEBUGLOG(5, "cwksp: reserving %p table %zd bytes, %zd bytes remaining",
alloc, bytes, ZSTD_cwksp_available_space(ws) - bytes);
assert((bytes & (sizeof(U32)-1)) == 0);
- ZSTD_cwksp_internal_advance_phase(ws, phase);
ZSTD_cwksp_assert_internal_consistency(ws);
assert(end <= top);
if (end > top) {
@@ -320,6 +401,8 @@ MEM_STATIC void* ZSTD_cwksp_reserve_table(ZSTD_cwksp* ws, size_t bytes) {
}
#endif
+ assert((bytes & (ZSTD_CWKSP_ALIGNMENT_BYTES-1)) == 0);
+ assert(((size_t)alloc & (ZSTD_CWKSP_ALIGNMENT_BYTES-1))== 0);
return alloc;
}
@@ -503,7 +586,7 @@ MEM_STATIC void ZSTD_cwksp_free(ZSTD_cwksp* ws, ZSTD_customMem customMem) {
/**
* Moves the management of a workspace from one cwksp to another. The src cwksp
- * is left in an invalid state (src must be re-init()'ed before its used again).
+ * is left in an invalid state (src must be re-init()'ed before it's used again).
*/
MEM_STATIC void ZSTD_cwksp_move(ZSTD_cwksp* dst, ZSTD_cwksp* src) {
*dst = *src;
@@ -527,6 +610,24 @@ MEM_STATIC int ZSTD_cwksp_reserve_failed(const ZSTD_cwksp* ws) {
* Functions Checking Free Space
***************************************/
+/* ZSTD_alignmentSpaceWithinBounds() :
+ * Returns if the estimated space needed for a wksp is within an acceptable limit of the
+ * actual amount of space used.
+ */
+MEM_STATIC int ZSTD_cwksp_estimated_space_within_bounds(const ZSTD_cwksp* const ws,
+ size_t const estimatedSpace, int resizedWorkspace) {
+ if (resizedWorkspace) {
+ /* Resized/newly allocated wksp should have exact bounds */
+ return ZSTD_cwksp_used(ws) == estimatedSpace;
+ } else {
+ /* Due to alignment, when reusing a workspace, we can actually consume 63 fewer or more bytes
+ * than estimatedSpace. See the comments in zstd_cwksp.h for details.
+ */
+ return (ZSTD_cwksp_used(ws) >= estimatedSpace - 63) && (ZSTD_cwksp_used(ws) <= estimatedSpace + 63);
+ }
+}
+
+
MEM_STATIC size_t ZSTD_cwksp_available_space(ZSTD_cwksp* ws) {
return (size_t)((BYTE*)ws->allocStart - (BYTE*)ws->tableEnd);
}
diff --git a/thirdparty/zstd/compress/zstd_double_fast.c b/thirdparty/zstd/compress/zstd_double_fast.c
index ef12a524f7..d0d3a784dd 100644
--- a/thirdparty/zstd/compress/zstd_double_fast.c
+++ b/thirdparty/zstd/compress/zstd_double_fast.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
@@ -409,7 +409,7 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic(
hashSmall[hSmall] = hashLong[hLong] = curr; /* update hash table */
if ((((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow : ensure repIndex doesn't overlap dict + prefix */
- & (repIndex > dictStartIndex))
+ & (offset_1 < curr+1 - dictStartIndex)) /* note: we are searching at curr+1 */
&& (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
const BYTE* repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend;
mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4;
@@ -477,7 +477,7 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic(
U32 const repIndex2 = current2 - offset_2;
const BYTE* repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2;
if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) /* intentional overflow : ensure repIndex2 doesn't overlap dict + prefix */
- & (repIndex2 > dictStartIndex))
+ & (offset_2 < current2 - dictStartIndex))
&& (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend;
size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4;
diff --git a/thirdparty/zstd/compress/zstd_double_fast.h b/thirdparty/zstd/compress/zstd_double_fast.h
index 14d944d69b..e16b7b03a3 100644
--- a/thirdparty/zstd/compress/zstd_double_fast.h
+++ b/thirdparty/zstd/compress/zstd_double_fast.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
diff --git a/thirdparty/zstd/compress/zstd_fast.c b/thirdparty/zstd/compress/zstd_fast.c
index db7ce83d0a..4edc04dccd 100644
--- a/thirdparty/zstd/compress/zstd_fast.c
+++ b/thirdparty/zstd/compress/zstd_fast.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
@@ -242,7 +242,7 @@ size_t ZSTD_compressBlock_fast_dictMatchState_generic(
assert(endIndex - prefixStartIndex <= maxDistance);
(void)maxDistance; (void)endIndex; /* these variables are not used when assert() is disabled */
- /* ensure there will be no no underflow
+ /* ensure there will be no underflow
* when translating a dict index into a local index */
assert(prefixStartIndex >= (U32)(dictEnd - dictBase));
@@ -416,9 +416,9 @@ static size_t ZSTD_compressBlock_fast_extDict_generic(
const BYTE* const repMatch = repBase + repIndex;
hashTable[h] = curr; /* update hash table */
DEBUGLOG(7, "offset_1 = %u , curr = %u", offset_1, curr);
- assert(offset_1 <= curr +1); /* check repIndex */
- if ( (((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > dictStartIndex))
+ if ( ( ((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow */
+ & (offset_1 < curr+1 - dictStartIndex) ) /* note: we are searching at curr+1 */
&& (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
const BYTE* const repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend;
size_t const rLength = ZSTD_count_2segments(ip+1 +4, repMatch +4, iend, repMatchEnd, prefixStart) + 4;
@@ -453,7 +453,7 @@ static size_t ZSTD_compressBlock_fast_extDict_generic(
U32 const current2 = (U32)(ip-base);
U32 const repIndex2 = current2 - offset_2;
const BYTE* const repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2;
- if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) & (repIndex2 > dictStartIndex)) /* intentional overflow */
+ if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) & (offset_2 < curr - dictStartIndex)) /* intentional overflow */
&& (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend;
size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4;
diff --git a/thirdparty/zstd/compress/zstd_fast.h b/thirdparty/zstd/compress/zstd_fast.h
index cf6aaa8e67..0d4a0c1090 100644
--- a/thirdparty/zstd/compress/zstd_fast.h
+++ b/thirdparty/zstd/compress/zstd_fast.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
diff --git a/thirdparty/zstd/compress/zstd_lazy.c b/thirdparty/zstd/compress/zstd_lazy.c
index 49ec1b09ef..3d523e8472 100644
--- a/thirdparty/zstd/compress/zstd_lazy.c
+++ b/thirdparty/zstd/compress/zstd_lazy.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
@@ -438,43 +438,9 @@ static size_t ZSTD_BtFindBestMatch_extDict_selectMLS (
}
}
-
-
-/* *********************************
-* Hash Chain
+/***********************************
+* Dedicated dict search
***********************************/
-#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & (mask)]
-
-/* Update chains up to ip (excluded)
- Assumption : always within prefix (i.e. not within extDict) */
-FORCE_INLINE_TEMPLATE U32 ZSTD_insertAndFindFirstIndex_internal(
- ZSTD_matchState_t* ms,
- const ZSTD_compressionParameters* const cParams,
- const BYTE* ip, U32 const mls)
-{
- U32* const hashTable = ms->hashTable;
- const U32 hashLog = cParams->hashLog;
- U32* const chainTable = ms->chainTable;
- const U32 chainMask = (1 << cParams->chainLog) - 1;
- const BYTE* const base = ms->window.base;
- const U32 target = (U32)(ip - base);
- U32 idx = ms->nextToUpdate;
-
- while(idx < target) { /* catch up */
- size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
- NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
- hashTable[h] = idx;
- idx++;
- }
-
- ms->nextToUpdate = target;
- return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
-}
-
-U32 ZSTD_insertAndFindFirstIndex(ZSTD_matchState_t* ms, const BYTE* ip) {
- const ZSTD_compressionParameters* const cParams = &ms->cParams;
- return ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, ms->cParams.minMatch);
-}
void ZSTD_dedicatedDictSearch_lazy_loadDictionary(ZSTD_matchState_t* ms, const BYTE* const ip)
{
@@ -500,11 +466,10 @@ void ZSTD_dedicatedDictSearch_lazy_loadDictionary(ZSTD_matchState_t* ms, const B
U32* const tmpChainTable = hashTable + ((size_t)1 << hashLog);
U32 const tmpChainSize = ((1 << ZSTD_LAZY_DDSS_BUCKET_LOG) - 1) << hashLog;
U32 const tmpMinChain = tmpChainSize < target ? target - tmpChainSize : idx;
-
U32 hashIdx;
assert(ms->cParams.chainLog <= 24);
- assert(ms->cParams.hashLog >= ms->cParams.chainLog);
+ assert(ms->cParams.hashLog > ms->cParams.chainLog);
assert(idx != 0);
assert(tmpMinChain <= minChain);
@@ -535,7 +500,7 @@ void ZSTD_dedicatedDictSearch_lazy_loadDictionary(ZSTD_matchState_t* ms, const B
if (count == cacheSize) {
for (count = 0; count < chainLimit;) {
if (i < minChain) {
- if (!i || countBeyondMinChain++ > cacheSize) {
+ if (!i || ++countBeyondMinChain > cacheSize) {
/* only allow pulling `cacheSize` number of entries
* into the cache or chainTable beyond `minChain`,
* to replace the entries pulled out of the
@@ -591,6 +556,139 @@ void ZSTD_dedicatedDictSearch_lazy_loadDictionary(ZSTD_matchState_t* ms, const B
ms->nextToUpdate = target;
}
+/* Returns the longest match length found in the dedicated dict search structure.
+ * If none are longer than the argument ml, then ml will be returned.
+ */
+FORCE_INLINE_TEMPLATE
+size_t ZSTD_dedicatedDictSearch_lazy_search(size_t* offsetPtr, size_t ml, U32 nbAttempts,
+ const ZSTD_matchState_t* const dms,
+ const BYTE* const ip, const BYTE* const iLimit,
+ const BYTE* const prefixStart, const U32 curr,
+ const U32 dictLimit, const size_t ddsIdx) {
+ const U32 ddsLowestIndex = dms->window.dictLimit;
+ const BYTE* const ddsBase = dms->window.base;
+ const BYTE* const ddsEnd = dms->window.nextSrc;
+ const U32 ddsSize = (U32)(ddsEnd - ddsBase);
+ const U32 ddsIndexDelta = dictLimit - ddsSize;
+ const U32 bucketSize = (1 << ZSTD_LAZY_DDSS_BUCKET_LOG);
+ const U32 bucketLimit = nbAttempts < bucketSize - 1 ? nbAttempts : bucketSize - 1;
+ U32 ddsAttempt;
+ U32 matchIndex;
+
+ for (ddsAttempt = 0; ddsAttempt < bucketSize - 1; ddsAttempt++) {
+ PREFETCH_L1(ddsBase + dms->hashTable[ddsIdx + ddsAttempt]);
+ }
+
+ {
+ U32 const chainPackedPointer = dms->hashTable[ddsIdx + bucketSize - 1];
+ U32 const chainIndex = chainPackedPointer >> 8;
+
+ PREFETCH_L1(&dms->chainTable[chainIndex]);
+ }
+
+ for (ddsAttempt = 0; ddsAttempt < bucketLimit; ddsAttempt++) {
+ size_t currentMl=0;
+ const BYTE* match;
+ matchIndex = dms->hashTable[ddsIdx + ddsAttempt];
+ match = ddsBase + matchIndex;
+
+ if (!matchIndex) {
+ return ml;
+ }
+
+ /* guaranteed by table construction */
+ (void)ddsLowestIndex;
+ assert(matchIndex >= ddsLowestIndex);
+ assert(match+4 <= ddsEnd);
+ if (MEM_read32(match) == MEM_read32(ip)) {
+ /* assumption : matchIndex <= dictLimit-4 (by table construction) */
+ currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, ddsEnd, prefixStart) + 4;
+ }
+
+ /* save best solution */
+ if (currentMl > ml) {
+ ml = currentMl;
+ *offsetPtr = curr - (matchIndex + ddsIndexDelta) + ZSTD_REP_MOVE;
+ if (ip+currentMl == iLimit) {
+ /* best possible, avoids read overflow on next attempt */
+ return ml;
+ }
+ }
+ }
+
+ {
+ U32 const chainPackedPointer = dms->hashTable[ddsIdx + bucketSize - 1];
+ U32 chainIndex = chainPackedPointer >> 8;
+ U32 const chainLength = chainPackedPointer & 0xFF;
+ U32 const chainAttempts = nbAttempts - ddsAttempt;
+ U32 const chainLimit = chainAttempts > chainLength ? chainLength : chainAttempts;
+ U32 chainAttempt;
+
+ for (chainAttempt = 0 ; chainAttempt < chainLimit; chainAttempt++) {
+ PREFETCH_L1(ddsBase + dms->chainTable[chainIndex + chainAttempt]);
+ }
+
+ for (chainAttempt = 0 ; chainAttempt < chainLimit; chainAttempt++, chainIndex++) {
+ size_t currentMl=0;
+ const BYTE* match;
+ matchIndex = dms->chainTable[chainIndex];
+ match = ddsBase + matchIndex;
+
+ /* guaranteed by table construction */
+ assert(matchIndex >= ddsLowestIndex);
+ assert(match+4 <= ddsEnd);
+ if (MEM_read32(match) == MEM_read32(ip)) {
+ /* assumption : matchIndex <= dictLimit-4 (by table construction) */
+ currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, ddsEnd, prefixStart) + 4;
+ }
+
+ /* save best solution */
+ if (currentMl > ml) {
+ ml = currentMl;
+ *offsetPtr = curr - (matchIndex + ddsIndexDelta) + ZSTD_REP_MOVE;
+ if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */
+ }
+ }
+ }
+ return ml;
+}
+
+
+/* *********************************
+* Hash Chain
+***********************************/
+#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & (mask)]
+
+/* Update chains up to ip (excluded)
+ Assumption : always within prefix (i.e. not within extDict) */
+FORCE_INLINE_TEMPLATE U32 ZSTD_insertAndFindFirstIndex_internal(
+ ZSTD_matchState_t* ms,
+ const ZSTD_compressionParameters* const cParams,
+ const BYTE* ip, U32 const mls)
+{
+ U32* const hashTable = ms->hashTable;
+ const U32 hashLog = cParams->hashLog;
+ U32* const chainTable = ms->chainTable;
+ const U32 chainMask = (1 << cParams->chainLog) - 1;
+ const BYTE* const base = ms->window.base;
+ const U32 target = (U32)(ip - base);
+ U32 idx = ms->nextToUpdate;
+
+ while(idx < target) { /* catch up */
+ size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
+ NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
+ hashTable[h] = idx;
+ idx++;
+ }
+
+ ms->nextToUpdate = target;
+ return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
+}
+
+U32 ZSTD_insertAndFindFirstIndex(ZSTD_matchState_t* ms, const BYTE* ip) {
+ const ZSTD_compressionParameters* const cParams = &ms->cParams;
+ return ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, ms->cParams.minMatch);
+}
/* inlining is important to hardwire a hot branch (template emulation) */
FORCE_INLINE_TEMPLATE
@@ -661,90 +759,8 @@ size_t ZSTD_HcFindBestMatch_generic (
}
if (dictMode == ZSTD_dedicatedDictSearch) {
- const U32 ddsLowestIndex = dms->window.dictLimit;
- const BYTE* const ddsBase = dms->window.base;
- const BYTE* const ddsEnd = dms->window.nextSrc;
- const U32 ddsSize = (U32)(ddsEnd - ddsBase);
- const U32 ddsIndexDelta = dictLimit - ddsSize;
- const U32 bucketSize = (1 << ZSTD_LAZY_DDSS_BUCKET_LOG);
- const U32 bucketLimit = nbAttempts < bucketSize - 1 ? nbAttempts : bucketSize - 1;
- U32 ddsAttempt;
-
- for (ddsAttempt = 0; ddsAttempt < bucketSize - 1; ddsAttempt++) {
- PREFETCH_L1(ddsBase + dms->hashTable[ddsIdx + ddsAttempt]);
- }
-
- {
- U32 const chainPackedPointer = dms->hashTable[ddsIdx + bucketSize - 1];
- U32 const chainIndex = chainPackedPointer >> 8;
-
- PREFETCH_L1(&dms->chainTable[chainIndex]);
- }
-
- for (ddsAttempt = 0; ddsAttempt < bucketLimit; ddsAttempt++) {
- size_t currentMl=0;
- const BYTE* match;
- matchIndex = dms->hashTable[ddsIdx + ddsAttempt];
- match = ddsBase + matchIndex;
-
- if (!matchIndex) {
- return ml;
- }
-
- /* guaranteed by table construction */
- (void)ddsLowestIndex;
- assert(matchIndex >= ddsLowestIndex);
- assert(match+4 <= ddsEnd);
- if (MEM_read32(match) == MEM_read32(ip)) {
- /* assumption : matchIndex <= dictLimit-4 (by table construction) */
- currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, ddsEnd, prefixStart) + 4;
- }
-
- /* save best solution */
- if (currentMl > ml) {
- ml = currentMl;
- *offsetPtr = curr - (matchIndex + ddsIndexDelta) + ZSTD_REP_MOVE;
- if (ip+currentMl == iLimit) {
- /* best possible, avoids read overflow on next attempt */
- return ml;
- }
- }
- }
-
- {
- U32 const chainPackedPointer = dms->hashTable[ddsIdx + bucketSize - 1];
- U32 chainIndex = chainPackedPointer >> 8;
- U32 const chainLength = chainPackedPointer & 0xFF;
- U32 const chainAttempts = nbAttempts - ddsAttempt;
- U32 const chainLimit = chainAttempts > chainLength ? chainLength : chainAttempts;
- U32 chainAttempt;
-
- for (chainAttempt = 0 ; chainAttempt < chainLimit; chainAttempt++) {
- PREFETCH_L1(ddsBase + dms->chainTable[chainIndex + chainAttempt]);
- }
-
- for (chainAttempt = 0 ; chainAttempt < chainLimit; chainAttempt++, chainIndex++) {
- size_t currentMl=0;
- const BYTE* match;
- matchIndex = dms->chainTable[chainIndex];
- match = ddsBase + matchIndex;
-
- /* guaranteed by table construction */
- assert(matchIndex >= ddsLowestIndex);
- assert(match+4 <= ddsEnd);
- if (MEM_read32(match) == MEM_read32(ip)) {
- /* assumption : matchIndex <= dictLimit-4 (by table construction) */
- currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, ddsEnd, prefixStart) + 4;
- }
-
- /* save best solution */
- if (currentMl > ml) {
- ml = currentMl;
- *offsetPtr = curr - (matchIndex + ddsIndexDelta) + ZSTD_REP_MOVE;
- if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */
- }
- }
- }
+ ml = ZSTD_dedicatedDictSearch_lazy_search(offsetPtr, ml, nbAttempts, dms,
+ ip, iLimit, prefixStart, curr, dictLimit, ddsIdx);
} else if (dictMode == ZSTD_dictMatchState) {
const U32* const dmsChainTable = dms->chainTable;
const U32 dmsChainSize = (1 << dms->cParams.chainLog);
@@ -845,11 +861,657 @@ FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
}
}
+/* *********************************
+* (SIMD) Row-based matchfinder
+***********************************/
+/* Constants for row-based hash */
+#define ZSTD_ROW_HASH_TAG_OFFSET 1 /* byte offset of hashes in the match state's tagTable from the beginning of a row */
+#define ZSTD_ROW_HASH_TAG_BITS 8 /* nb bits to use for the tag */
+#define ZSTD_ROW_HASH_TAG_MASK ((1u << ZSTD_ROW_HASH_TAG_BITS) - 1)
+
+#define ZSTD_ROW_HASH_CACHE_MASK (ZSTD_ROW_HASH_CACHE_SIZE - 1)
+
+typedef U32 ZSTD_VecMask; /* Clarifies when we are interacting with a U32 representing a mask of matches */
+
+#if !defined(ZSTD_NO_INTRINSICS) && defined(__SSE2__) /* SIMD SSE version */
+
+#include <emmintrin.h>
+typedef __m128i ZSTD_Vec128;
+
+/* Returns a 128-bit container with 128-bits from src */
+static ZSTD_Vec128 ZSTD_Vec128_read(const void* const src) {
+ return _mm_loadu_si128((ZSTD_Vec128 const*)src);
+}
+
+/* Returns a ZSTD_Vec128 with the byte "val" packed 16 times */
+static ZSTD_Vec128 ZSTD_Vec128_set8(BYTE val) {
+ return _mm_set1_epi8((char)val);
+}
+
+/* Do byte-by-byte comparison result of x and y. Then collapse 128-bit resultant mask
+ * into a 32-bit mask that is the MSB of each byte.
+ * */
+static ZSTD_VecMask ZSTD_Vec128_cmpMask8(ZSTD_Vec128 x, ZSTD_Vec128 y) {
+ return (ZSTD_VecMask)_mm_movemask_epi8(_mm_cmpeq_epi8(x, y));
+}
+
+typedef struct {
+ __m128i fst;
+ __m128i snd;
+} ZSTD_Vec256;
+
+static ZSTD_Vec256 ZSTD_Vec256_read(const void* const ptr) {
+ ZSTD_Vec256 v;
+ v.fst = ZSTD_Vec128_read(ptr);
+ v.snd = ZSTD_Vec128_read((ZSTD_Vec128 const*)ptr + 1);
+ return v;
+}
+
+static ZSTD_Vec256 ZSTD_Vec256_set8(BYTE val) {
+ ZSTD_Vec256 v;
+ v.fst = ZSTD_Vec128_set8(val);
+ v.snd = ZSTD_Vec128_set8(val);
+ return v;
+}
+
+static ZSTD_VecMask ZSTD_Vec256_cmpMask8(ZSTD_Vec256 x, ZSTD_Vec256 y) {
+ ZSTD_VecMask fstMask;
+ ZSTD_VecMask sndMask;
+ fstMask = ZSTD_Vec128_cmpMask8(x.fst, y.fst);
+ sndMask = ZSTD_Vec128_cmpMask8(x.snd, y.snd);
+ return fstMask | (sndMask << 16);
+}
+
+#elif !defined(ZSTD_NO_INTRINSICS) && defined(__ARM_NEON) /* SIMD ARM NEON Version */
+
+#include <arm_neon.h>
+typedef uint8x16_t ZSTD_Vec128;
+
+static ZSTD_Vec128 ZSTD_Vec128_read(const void* const src) {
+ return vld1q_u8((const BYTE* const)src);
+}
+
+static ZSTD_Vec128 ZSTD_Vec128_set8(BYTE val) {
+ return vdupq_n_u8(val);
+}
+
+/* Mimics '_mm_movemask_epi8()' from SSE */
+static U32 ZSTD_vmovmaskq_u8(ZSTD_Vec128 val) {
+ /* Shift out everything but the MSB bits in each byte */
+ uint16x8_t highBits = vreinterpretq_u16_u8(vshrq_n_u8(val, 7));
+ /* Merge the even lanes together with vsra (right shift and add) */
+ uint32x4_t paired16 = vreinterpretq_u32_u16(vsraq_n_u16(highBits, highBits, 7));
+ uint64x2_t paired32 = vreinterpretq_u64_u32(vsraq_n_u32(paired16, paired16, 14));
+ uint8x16_t paired64 = vreinterpretq_u8_u64(vsraq_n_u64(paired32, paired32, 28));
+ /* Extract the low 8 bits from each lane, merge */
+ return vgetq_lane_u8(paired64, 0) | ((U32)vgetq_lane_u8(paired64, 8) << 8);
+}
+
+static ZSTD_VecMask ZSTD_Vec128_cmpMask8(ZSTD_Vec128 x, ZSTD_Vec128 y) {
+ return (ZSTD_VecMask)ZSTD_vmovmaskq_u8(vceqq_u8(x, y));
+}
+
+typedef struct {
+ uint8x16_t fst;
+ uint8x16_t snd;
+} ZSTD_Vec256;
+
+static ZSTD_Vec256 ZSTD_Vec256_read(const void* const ptr) {
+ ZSTD_Vec256 v;
+ v.fst = ZSTD_Vec128_read(ptr);
+ v.snd = ZSTD_Vec128_read((ZSTD_Vec128 const*)ptr + 1);
+ return v;
+}
+
+static ZSTD_Vec256 ZSTD_Vec256_set8(BYTE val) {
+ ZSTD_Vec256 v;
+ v.fst = ZSTD_Vec128_set8(val);
+ v.snd = ZSTD_Vec128_set8(val);
+ return v;
+}
+
+static ZSTD_VecMask ZSTD_Vec256_cmpMask8(ZSTD_Vec256 x, ZSTD_Vec256 y) {
+ ZSTD_VecMask fstMask;
+ ZSTD_VecMask sndMask;
+ fstMask = ZSTD_Vec128_cmpMask8(x.fst, y.fst);
+ sndMask = ZSTD_Vec128_cmpMask8(x.snd, y.snd);
+ return fstMask | (sndMask << 16);
+}
+
+#else /* Scalar fallback version */
+
+#define VEC128_NB_SIZE_T (16 / sizeof(size_t))
+typedef struct {
+ size_t vec[VEC128_NB_SIZE_T];
+} ZSTD_Vec128;
+
+static ZSTD_Vec128 ZSTD_Vec128_read(const void* const src) {
+ ZSTD_Vec128 ret;
+ ZSTD_memcpy(ret.vec, src, VEC128_NB_SIZE_T*sizeof(size_t));
+ return ret;
+}
+
+static ZSTD_Vec128 ZSTD_Vec128_set8(BYTE val) {
+ ZSTD_Vec128 ret = { {0} };
+ int startBit = sizeof(size_t) * 8 - 8;
+ for (;startBit >= 0; startBit -= 8) {
+ unsigned j = 0;
+ for (;j < VEC128_NB_SIZE_T; ++j) {
+ ret.vec[j] |= ((size_t)val << startBit);
+ }
+ }
+ return ret;
+}
+
+/* Compare x to y, byte by byte, generating a "matches" bitfield */
+static ZSTD_VecMask ZSTD_Vec128_cmpMask8(ZSTD_Vec128 x, ZSTD_Vec128 y) {
+ ZSTD_VecMask res = 0;
+ unsigned i = 0;
+ unsigned l = 0;
+ for (; i < VEC128_NB_SIZE_T; ++i) {
+ const size_t cmp1 = x.vec[i];
+ const size_t cmp2 = y.vec[i];
+ unsigned j = 0;
+ for (; j < sizeof(size_t); ++j, ++l) {
+ if (((cmp1 >> j*8) & 0xFF) == ((cmp2 >> j*8) & 0xFF)) {
+ res |= ((U32)1 << (j+i*sizeof(size_t)));
+ }
+ }
+ }
+ return res;
+}
+
+#define VEC256_NB_SIZE_T 2*VEC128_NB_SIZE_T
+typedef struct {
+ size_t vec[VEC256_NB_SIZE_T];
+} ZSTD_Vec256;
+
+static ZSTD_Vec256 ZSTD_Vec256_read(const void* const src) {
+ ZSTD_Vec256 ret;
+ ZSTD_memcpy(ret.vec, src, VEC256_NB_SIZE_T*sizeof(size_t));
+ return ret;
+}
+
+static ZSTD_Vec256 ZSTD_Vec256_set8(BYTE val) {
+ ZSTD_Vec256 ret = { {0} };
+ int startBit = sizeof(size_t) * 8 - 8;
+ for (;startBit >= 0; startBit -= 8) {
+ unsigned j = 0;
+ for (;j < VEC256_NB_SIZE_T; ++j) {
+ ret.vec[j] |= ((size_t)val << startBit);
+ }
+ }
+ return ret;
+}
+
+/* Compare x to y, byte by byte, generating a "matches" bitfield */
+static ZSTD_VecMask ZSTD_Vec256_cmpMask8(ZSTD_Vec256 x, ZSTD_Vec256 y) {
+ ZSTD_VecMask res = 0;
+ unsigned i = 0;
+ unsigned l = 0;
+ for (; i < VEC256_NB_SIZE_T; ++i) {
+ const size_t cmp1 = x.vec[i];
+ const size_t cmp2 = y.vec[i];
+ unsigned j = 0;
+ for (; j < sizeof(size_t); ++j, ++l) {
+ if (((cmp1 >> j*8) & 0xFF) == ((cmp2 >> j*8) & 0xFF)) {
+ res |= ((U32)1 << (j+i*sizeof(size_t)));
+ }
+ }
+ }
+ return res;
+}
+
+#endif /* !defined(ZSTD_NO_INTRINSICS) && defined(__SSE2__) */
+
+/* ZSTD_VecMask_next():
+ * Starting from the LSB, returns the idx of the next non-zero bit.
+ * Basically counting the nb of trailing zeroes.
+ */
+static U32 ZSTD_VecMask_next(ZSTD_VecMask val) {
+# if defined(_MSC_VER) /* Visual */
+ unsigned long r=0;
+ return _BitScanForward(&r, val) ? (U32)r : 0;
+# elif defined(__GNUC__) && (__GNUC__ >= 3)
+ return (U32)__builtin_ctz(val);
+# else
+ /* Software ctz version: http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightMultLookup */
+ static const U32 multiplyDeBruijnBitPosition[32] =
+ {
+ 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
+ 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
+ };
+ return multiplyDeBruijnBitPosition[((U32)((v & -(int)v) * 0x077CB531U)) >> 27];
+# endif
+}
+
+/* ZSTD_VecMask_rotateRight():
+ * Rotates a bitfield to the right by "rotation" bits.
+ * If the rotation is greater than totalBits, the returned mask is 0.
+ */
+FORCE_INLINE_TEMPLATE ZSTD_VecMask
+ZSTD_VecMask_rotateRight(ZSTD_VecMask mask, U32 const rotation, U32 const totalBits) {
+ if (rotation == 0)
+ return mask;
+ switch (totalBits) {
+ default:
+ assert(0);
+ case 16:
+ return (mask >> rotation) | (U16)(mask << (16 - rotation));
+ case 32:
+ return (mask >> rotation) | (U32)(mask << (32 - rotation));
+ }
+}
+
+/* ZSTD_row_nextIndex():
+ * Returns the next index to insert at within a tagTable row, and updates the "head"
+ * value to reflect the update. Essentially cycles backwards from [0, {entries per row})
+ */
+FORCE_INLINE_TEMPLATE U32 ZSTD_row_nextIndex(BYTE* const tagRow, U32 const rowMask) {
+ U32 const next = (*tagRow - 1) & rowMask;
+ *tagRow = (BYTE)next;
+ return next;
+}
+
+/* ZSTD_isAligned():
+ * Checks that a pointer is aligned to "align" bytes which must be a power of 2.
+ */
+MEM_STATIC int ZSTD_isAligned(void const* ptr, size_t align) {
+ assert((align & (align - 1)) == 0);
+ return (((size_t)ptr) & (align - 1)) == 0;
+}
+
+/* ZSTD_row_prefetch():
+ * Performs prefetching for the hashTable and tagTable at a given row.
+ */
+FORCE_INLINE_TEMPLATE void ZSTD_row_prefetch(U32 const* hashTable, U16 const* tagTable, U32 const relRow, U32 const rowLog) {
+ PREFETCH_L1(hashTable + relRow);
+ if (rowLog == 5) {
+ PREFETCH_L1(hashTable + relRow + 16);
+ }
+ PREFETCH_L1(tagTable + relRow);
+ assert(rowLog == 4 || rowLog == 5);
+ assert(ZSTD_isAligned(hashTable + relRow, 64)); /* prefetched hash row always 64-byte aligned */
+ assert(ZSTD_isAligned(tagTable + relRow, (size_t)1 << rowLog)); /* prefetched tagRow sits on a multiple of 32 or 64 bytes */
+}
+
+/* ZSTD_row_fillHashCache():
+ * Fill up the hash cache starting at idx, prefetching up to ZSTD_ROW_HASH_CACHE_SIZE entries,
+ * but not beyond iLimit.
+ */
+static void ZSTD_row_fillHashCache(ZSTD_matchState_t* ms, const BYTE* base,
+ U32 const rowLog, U32 const mls,
+ U32 idx, const BYTE* const iLimit)
+{
+ U32 const* const hashTable = ms->hashTable;
+ U16 const* const tagTable = ms->tagTable;
+ U32 const hashLog = ms->rowHashLog;
+ U32 const maxElemsToPrefetch = (base + idx) > iLimit ? 0 : (U32)(iLimit - (base + idx) + 1);
+ U32 const lim = idx + MIN(ZSTD_ROW_HASH_CACHE_SIZE, maxElemsToPrefetch);
+
+ for (; idx < lim; ++idx) {
+ U32 const hash = (U32)ZSTD_hashPtr(base + idx, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls);
+ U32 const row = (hash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog;
+ ZSTD_row_prefetch(hashTable, tagTable, row, rowLog);
+ ms->hashCache[idx & ZSTD_ROW_HASH_CACHE_MASK] = hash;
+ }
+
+ DEBUGLOG(6, "ZSTD_row_fillHashCache(): [%u %u %u %u %u %u %u %u]", ms->hashCache[0], ms->hashCache[1],
+ ms->hashCache[2], ms->hashCache[3], ms->hashCache[4],
+ ms->hashCache[5], ms->hashCache[6], ms->hashCache[7]);
+}
+
+/* ZSTD_row_nextCachedHash():
+ * Returns the hash of base + idx, and replaces the hash in the hash cache with the byte at
+ * base + idx + ZSTD_ROW_HASH_CACHE_SIZE. Also prefetches the appropriate rows from hashTable and tagTable.
+ */
+FORCE_INLINE_TEMPLATE U32 ZSTD_row_nextCachedHash(U32* cache, U32 const* hashTable,
+ U16 const* tagTable, BYTE const* base,
+ U32 idx, U32 const hashLog,
+ U32 const rowLog, U32 const mls)
+{
+ U32 const newHash = (U32)ZSTD_hashPtr(base+idx+ZSTD_ROW_HASH_CACHE_SIZE, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls);
+ U32 const row = (newHash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog;
+ ZSTD_row_prefetch(hashTable, tagTable, row, rowLog);
+ { U32 const hash = cache[idx & ZSTD_ROW_HASH_CACHE_MASK];
+ cache[idx & ZSTD_ROW_HASH_CACHE_MASK] = newHash;
+ return hash;
+ }
+}
+
+/* ZSTD_row_update_internal():
+ * Inserts the byte at ip into the appropriate position in the hash table.
+ * Determines the relative row, and the position within the {16, 32} entry row to insert at.
+ */
+FORCE_INLINE_TEMPLATE void ZSTD_row_update_internal(ZSTD_matchState_t* ms, const BYTE* ip,
+ U32 const mls, U32 const rowLog,
+ U32 const rowMask, U32 const useCache)
+{
+ U32* const hashTable = ms->hashTable;
+ U16* const tagTable = ms->tagTable;
+ U32 const hashLog = ms->rowHashLog;
+ const BYTE* const base = ms->window.base;
+ const U32 target = (U32)(ip - base);
+ U32 idx = ms->nextToUpdate;
+
+ DEBUGLOG(6, "ZSTD_row_update_internal(): nextToUpdate=%u, current=%u", idx, target);
+ for (; idx < target; ++idx) {
+ U32 const hash = useCache ? ZSTD_row_nextCachedHash(ms->hashCache, hashTable, tagTable, base, idx, hashLog, rowLog, mls)
+ : (U32)ZSTD_hashPtr(base + idx, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls);
+ U32 const relRow = (hash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog;
+ U32* const row = hashTable + relRow;
+ BYTE* tagRow = (BYTE*)(tagTable + relRow); /* Though tagTable is laid out as a table of U16, each tag is only 1 byte.
+ Explicit cast allows us to get exact desired position within each row */
+ U32 const pos = ZSTD_row_nextIndex(tagRow, rowMask);
+
+ assert(hash == ZSTD_hashPtr(base + idx, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls));
+ ((BYTE*)tagRow)[pos + ZSTD_ROW_HASH_TAG_OFFSET] = hash & ZSTD_ROW_HASH_TAG_MASK;
+ row[pos] = idx;
+ }
+ ms->nextToUpdate = target;
+}
+
+/* ZSTD_row_update():
+ * External wrapper for ZSTD_row_update_internal(). Used for filling the hashtable during dictionary
+ * processing.
+ */
+void ZSTD_row_update(ZSTD_matchState_t* const ms, const BYTE* ip) {
+ const U32 rowLog = ms->cParams.searchLog < 5 ? 4 : 5;
+ const U32 rowMask = (1u << rowLog) - 1;
+ const U32 mls = MIN(ms->cParams.minMatch, 6 /* mls caps out at 6 */);
+
+ DEBUGLOG(5, "ZSTD_row_update(), rowLog=%u", rowLog);
+ ZSTD_row_update_internal(ms, ip, mls, rowLog, rowMask, 0 /* dont use cache */);
+}
+
+/* Returns a ZSTD_VecMask (U32) that has the nth bit set to 1 if the newly-computed "tag" matches
+ * the hash at the nth position in a row of the tagTable.
+ */
+FORCE_INLINE_TEMPLATE
+ZSTD_VecMask ZSTD_row_getMatchMask(const BYTE* const tagRow, const BYTE tag, const U32 head, const U32 rowEntries) {
+ ZSTD_VecMask matches = 0;
+ if (rowEntries == 16) {
+ ZSTD_Vec128 hashes = ZSTD_Vec128_read(tagRow + ZSTD_ROW_HASH_TAG_OFFSET);
+ ZSTD_Vec128 expandedTags = ZSTD_Vec128_set8(tag);
+ matches = ZSTD_Vec128_cmpMask8(hashes, expandedTags);
+ } else if (rowEntries == 32) {
+ ZSTD_Vec256 hashes = ZSTD_Vec256_read(tagRow + ZSTD_ROW_HASH_TAG_OFFSET);
+ ZSTD_Vec256 expandedTags = ZSTD_Vec256_set8(tag);
+ matches = ZSTD_Vec256_cmpMask8(hashes, expandedTags);
+ } else {
+ assert(0);
+ }
+ /* Each row is a circular buffer beginning at the value of "head". So we must rotate the "matches" bitfield
+ to match up with the actual layout of the entries within the hashTable */
+ return ZSTD_VecMask_rotateRight(matches, head, rowEntries);
+}
+
+/* The high-level approach of the SIMD row based match finder is as follows:
+ * - Figure out where to insert the new entry:
+ * - Generate a hash from a byte along with an additional 1-byte "short hash". The additional byte is our "tag"
+ * - The hashTable is effectively split into groups or "rows" of 16 or 32 entries of U32, and the hash determines
+ * which row to insert into.
+ * - Determine the correct position within the row to insert the entry into. Each row of 16 or 32 can
+ * be considered as a circular buffer with a "head" index that resides in the tagTable.
+ * - Also insert the "tag" into the equivalent row and position in the tagTable.
+ * - Note: The tagTable has 17 or 33 1-byte entries per row, due to 16 or 32 tags, and 1 "head" entry.
+ * The 17 or 33 entry rows are spaced out to occur every 32 or 64 bytes, respectively,
+ * for alignment/performance reasons, leaving some bytes unused.
+ * - Use SIMD to efficiently compare the tags in the tagTable to the 1-byte "short hash" and
+ * generate a bitfield that we can cycle through to check the collisions in the hash table.
+ * - Pick the longest match.
+ */
+FORCE_INLINE_TEMPLATE
+size_t ZSTD_RowFindBestMatch_generic (
+ ZSTD_matchState_t* ms,
+ const BYTE* const ip, const BYTE* const iLimit,
+ size_t* offsetPtr,
+ const U32 mls, const ZSTD_dictMode_e dictMode,
+ const U32 rowLog)
+{
+ U32* const hashTable = ms->hashTable;
+ U16* const tagTable = ms->tagTable;
+ U32* const hashCache = ms->hashCache;
+ const U32 hashLog = ms->rowHashLog;
+ const ZSTD_compressionParameters* const cParams = &ms->cParams;
+ const BYTE* const base = ms->window.base;
+ const BYTE* const dictBase = ms->window.dictBase;
+ const U32 dictLimit = ms->window.dictLimit;
+ const BYTE* const prefixStart = base + dictLimit;
+ const BYTE* const dictEnd = dictBase + dictLimit;
+ const U32 curr = (U32)(ip-base);
+ const U32 maxDistance = 1U << cParams->windowLog;
+ const U32 lowestValid = ms->window.lowLimit;
+ const U32 withinMaxDistance = (curr - lowestValid > maxDistance) ? curr - maxDistance : lowestValid;
+ const U32 isDictionary = (ms->loadedDictEnd != 0);
+ const U32 lowLimit = isDictionary ? lowestValid : withinMaxDistance;
+ const U32 rowEntries = (1U << rowLog);
+ const U32 rowMask = rowEntries - 1;
+ const U32 cappedSearchLog = MIN(cParams->searchLog, rowLog); /* nb of searches is capped at nb entries per row */
+ U32 nbAttempts = 1U << cappedSearchLog;
+ size_t ml=4-1;
+
+ /* DMS/DDS variables that may be referenced laster */
+ const ZSTD_matchState_t* const dms = ms->dictMatchState;
+ size_t ddsIdx;
+ U32 ddsExtraAttempts; /* cctx hash tables are limited in searches, but allow extra searches into DDS */
+ U32 dmsTag;
+ U32* dmsRow;
+ BYTE* dmsTagRow;
+
+ if (dictMode == ZSTD_dedicatedDictSearch) {
+ const U32 ddsHashLog = dms->cParams.hashLog - ZSTD_LAZY_DDSS_BUCKET_LOG;
+ { /* Prefetch DDS hashtable entry */
+ ddsIdx = ZSTD_hashPtr(ip, ddsHashLog, mls) << ZSTD_LAZY_DDSS_BUCKET_LOG;
+ PREFETCH_L1(&dms->hashTable[ddsIdx]);
+ }
+ ddsExtraAttempts = cParams->searchLog > rowLog ? 1U << (cParams->searchLog - rowLog) : 0;
+ }
+
+ if (dictMode == ZSTD_dictMatchState) {
+ /* Prefetch DMS rows */
+ U32* const dmsHashTable = dms->hashTable;
+ U16* const dmsTagTable = dms->tagTable;
+ U32 const dmsHash = (U32)ZSTD_hashPtr(ip, dms->rowHashLog + ZSTD_ROW_HASH_TAG_BITS, mls);
+ U32 const dmsRelRow = (dmsHash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog;
+ dmsTag = dmsHash & ZSTD_ROW_HASH_TAG_MASK;
+ dmsTagRow = (BYTE*)(dmsTagTable + dmsRelRow);
+ dmsRow = dmsHashTable + dmsRelRow;
+ ZSTD_row_prefetch(dmsHashTable, dmsTagTable, dmsRelRow, rowLog);
+ }
+
+ /* Update the hashTable and tagTable up to (but not including) ip */
+ ZSTD_row_update_internal(ms, ip, mls, rowLog, rowMask, 1 /* useCache */);
+ { /* Get the hash for ip, compute the appropriate row */
+ U32 const hash = ZSTD_row_nextCachedHash(hashCache, hashTable, tagTable, base, curr, hashLog, rowLog, mls);
+ U32 const relRow = (hash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog;
+ U32 const tag = hash & ZSTD_ROW_HASH_TAG_MASK;
+ U32* const row = hashTable + relRow;
+ BYTE* tagRow = (BYTE*)(tagTable + relRow);
+ U32 const head = *tagRow & rowMask;
+ U32 matchBuffer[32 /* maximum nb entries per row */];
+ size_t numMatches = 0;
+ size_t currMatch = 0;
+ ZSTD_VecMask matches = ZSTD_row_getMatchMask(tagRow, (BYTE)tag, head, rowEntries);
+
+ /* Cycle through the matches and prefetch */
+ for (; (matches > 0) && (nbAttempts > 0); --nbAttempts, matches &= (matches - 1)) {
+ U32 const matchPos = (head + ZSTD_VecMask_next(matches)) & rowMask;
+ U32 const matchIndex = row[matchPos];
+ assert(numMatches < rowEntries);
+ if (matchIndex < lowLimit)
+ break;
+ if ((dictMode != ZSTD_extDict) || matchIndex >= dictLimit) {
+ PREFETCH_L1(base + matchIndex);
+ } else {
+ PREFETCH_L1(dictBase + matchIndex);
+ }
+ matchBuffer[numMatches++] = matchIndex;
+ }
+
+ /* Speed opt: insert current byte into hashtable too. This allows us to avoid one iteration of the loop
+ in ZSTD_row_update_internal() at the next search. */
+ {
+ U32 const pos = ZSTD_row_nextIndex(tagRow, rowMask);
+ tagRow[pos + ZSTD_ROW_HASH_TAG_OFFSET] = (BYTE)tag;
+ row[pos] = ms->nextToUpdate++;
+ }
+
+ /* Return the longest match */
+ for (; currMatch < numMatches; ++currMatch) {
+ U32 const matchIndex = matchBuffer[currMatch];
+ size_t currentMl=0;
+ assert(matchIndex < curr);
+ assert(matchIndex >= lowLimit);
+
+ if ((dictMode != ZSTD_extDict) || matchIndex >= dictLimit) {
+ const BYTE* const match = base + matchIndex;
+ assert(matchIndex >= dictLimit); /* ensures this is true if dictMode != ZSTD_extDict */
+ if (match[ml] == ip[ml]) /* potentially better */
+ currentMl = ZSTD_count(ip, match, iLimit);
+ } else {
+ const BYTE* const match = dictBase + matchIndex;
+ assert(match+4 <= dictEnd);
+ if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
+ currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dictEnd, prefixStart) + 4;
+ }
+
+ /* Save best solution */
+ if (currentMl > ml) {
+ ml = currentMl;
+ *offsetPtr = curr - matchIndex + ZSTD_REP_MOVE;
+ if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */
+ }
+ }
+ }
+
+ if (dictMode == ZSTD_dedicatedDictSearch) {
+ ml = ZSTD_dedicatedDictSearch_lazy_search(offsetPtr, ml, nbAttempts + ddsExtraAttempts, dms,
+ ip, iLimit, prefixStart, curr, dictLimit, ddsIdx);
+ } else if (dictMode == ZSTD_dictMatchState) {
+ /* TODO: Measure and potentially add prefetching to DMS */
+ const U32 dmsLowestIndex = dms->window.dictLimit;
+ const BYTE* const dmsBase = dms->window.base;
+ const BYTE* const dmsEnd = dms->window.nextSrc;
+ const U32 dmsSize = (U32)(dmsEnd - dmsBase);
+ const U32 dmsIndexDelta = dictLimit - dmsSize;
+
+ { U32 const head = *dmsTagRow & rowMask;
+ U32 matchBuffer[32 /* maximum nb row entries */];
+ size_t numMatches = 0;
+ size_t currMatch = 0;
+ ZSTD_VecMask matches = ZSTD_row_getMatchMask(dmsTagRow, (BYTE)dmsTag, head, rowEntries);
+
+ for (; (matches > 0) && (nbAttempts > 0); --nbAttempts, matches &= (matches - 1)) {
+ U32 const matchPos = (head + ZSTD_VecMask_next(matches)) & rowMask;
+ U32 const matchIndex = dmsRow[matchPos];
+ if (matchIndex < dmsLowestIndex)
+ break;
+ PREFETCH_L1(dmsBase + matchIndex);
+ matchBuffer[numMatches++] = matchIndex;
+ }
+
+ /* Return the longest match */
+ for (; currMatch < numMatches; ++currMatch) {
+ U32 const matchIndex = matchBuffer[currMatch];
+ size_t currentMl=0;
+ assert(matchIndex >= dmsLowestIndex);
+ assert(matchIndex < curr);
+
+ { const BYTE* const match = dmsBase + matchIndex;
+ assert(match+4 <= dmsEnd);
+ if (MEM_read32(match) == MEM_read32(ip))
+ currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dmsEnd, prefixStart) + 4;
+ }
+
+ if (currentMl > ml) {
+ ml = currentMl;
+ *offsetPtr = curr - (matchIndex + dmsIndexDelta) + ZSTD_REP_MOVE;
+ if (ip+currentMl == iLimit) break;
+ }
+ }
+ }
+ }
+ return ml;
+}
+
+/* Inlining is important to hardwire a hot branch (template emulation) */
+FORCE_INLINE_TEMPLATE size_t ZSTD_RowFindBestMatch_selectMLS (
+ ZSTD_matchState_t* ms,
+ const BYTE* ip, const BYTE* const iLimit,
+ const ZSTD_dictMode_e dictMode, size_t* offsetPtr, const U32 rowLog)
+{
+ switch(ms->cParams.minMatch)
+ {
+ default : /* includes case 3 */
+ case 4 : return ZSTD_RowFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 4, dictMode, rowLog);
+ case 5 : return ZSTD_RowFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 5, dictMode, rowLog);
+ case 7 :
+ case 6 : return ZSTD_RowFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 6, dictMode, rowLog);
+ }
+}
+
+FORCE_INLINE_TEMPLATE size_t ZSTD_RowFindBestMatch_selectRowLog (
+ ZSTD_matchState_t* ms,
+ const BYTE* ip, const BYTE* const iLimit,
+ size_t* offsetPtr)
+{
+ const U32 cappedSearchLog = MIN(ms->cParams.searchLog, 5);
+ switch(cappedSearchLog)
+ {
+ default :
+ case 4 : return ZSTD_RowFindBestMatch_selectMLS(ms, ip, iLimit, ZSTD_noDict, offsetPtr, 4);
+ case 5 : return ZSTD_RowFindBestMatch_selectMLS(ms, ip, iLimit, ZSTD_noDict, offsetPtr, 5);
+ }
+}
+
+FORCE_INLINE_TEMPLATE size_t ZSTD_RowFindBestMatch_dictMatchState_selectRowLog(
+ ZSTD_matchState_t* ms,
+ const BYTE* ip, const BYTE* const iLimit,
+ size_t* offsetPtr)
+{
+ const U32 cappedSearchLog = MIN(ms->cParams.searchLog, 5);
+ switch(cappedSearchLog)
+ {
+ default :
+ case 4 : return ZSTD_RowFindBestMatch_selectMLS(ms, ip, iLimit, ZSTD_dictMatchState, offsetPtr, 4);
+ case 5 : return ZSTD_RowFindBestMatch_selectMLS(ms, ip, iLimit, ZSTD_dictMatchState, offsetPtr, 5);
+ }
+}
+
+FORCE_INLINE_TEMPLATE size_t ZSTD_RowFindBestMatch_dedicatedDictSearch_selectRowLog(
+ ZSTD_matchState_t* ms,
+ const BYTE* ip, const BYTE* const iLimit,
+ size_t* offsetPtr)
+{
+ const U32 cappedSearchLog = MIN(ms->cParams.searchLog, 5);
+ switch(cappedSearchLog)
+ {
+ default :
+ case 4 : return ZSTD_RowFindBestMatch_selectMLS(ms, ip, iLimit, ZSTD_dedicatedDictSearch, offsetPtr, 4);
+ case 5 : return ZSTD_RowFindBestMatch_selectMLS(ms, ip, iLimit, ZSTD_dedicatedDictSearch, offsetPtr, 5);
+ }
+}
+
+FORCE_INLINE_TEMPLATE size_t ZSTD_RowFindBestMatch_extDict_selectRowLog (
+ ZSTD_matchState_t* ms,
+ const BYTE* ip, const BYTE* const iLimit,
+ size_t* offsetPtr)
+{
+ const U32 cappedSearchLog = MIN(ms->cParams.searchLog, 5);
+ switch(cappedSearchLog)
+ {
+ default :
+ case 4 : return ZSTD_RowFindBestMatch_selectMLS(ms, ip, iLimit, ZSTD_extDict, offsetPtr, 4);
+ case 5 : return ZSTD_RowFindBestMatch_selectMLS(ms, ip, iLimit, ZSTD_extDict, offsetPtr, 5);
+ }
+}
+
/* *******************************
* Common parser - lazy strategy
*********************************/
-typedef enum { search_hashChain, search_binaryTree } searchMethod_e;
+typedef enum { search_hashChain=0, search_binaryTree=1, search_rowHash=2 } searchMethod_e;
FORCE_INLINE_TEMPLATE size_t
ZSTD_compressBlock_lazy_generic(
@@ -863,10 +1525,11 @@ ZSTD_compressBlock_lazy_generic(
const BYTE* ip = istart;
const BYTE* anchor = istart;
const BYTE* const iend = istart + srcSize;
- const BYTE* const ilimit = iend - 8;
+ const BYTE* const ilimit = searchMethod == search_rowHash ? iend - 8 - ZSTD_ROW_HASH_CACHE_SIZE : iend - 8;
const BYTE* const base = ms->window.base;
const U32 prefixLowestIndex = ms->window.dictLimit;
const BYTE* const prefixLowest = base + prefixLowestIndex;
+ const U32 rowLog = ms->cParams.searchLog < 5 ? 4 : 5;
typedef size_t (*searchMax_f)(
ZSTD_matchState_t* ms,
@@ -878,26 +1541,30 @@ ZSTD_compressBlock_lazy_generic(
* that should never occur (extDict modes go to the other implementation
* below and there is no DDSS for binary tree search yet).
*/
- const searchMax_f searchFuncs[4][2] = {
+ const searchMax_f searchFuncs[4][3] = {
{
ZSTD_HcFindBestMatch_selectMLS,
- ZSTD_BtFindBestMatch_selectMLS
+ ZSTD_BtFindBestMatch_selectMLS,
+ ZSTD_RowFindBestMatch_selectRowLog
},
{
NULL,
+ NULL,
NULL
},
{
ZSTD_HcFindBestMatch_dictMatchState_selectMLS,
- ZSTD_BtFindBestMatch_dictMatchState_selectMLS
+ ZSTD_BtFindBestMatch_dictMatchState_selectMLS,
+ ZSTD_RowFindBestMatch_dictMatchState_selectRowLog
},
{
ZSTD_HcFindBestMatch_dedicatedDictSearch_selectMLS,
- NULL
+ NULL,
+ ZSTD_RowFindBestMatch_dedicatedDictSearch_selectRowLog
}
};
- searchMax_f const searchMax = searchFuncs[dictMode][searchMethod == search_binaryTree];
+ searchMax_f const searchMax = searchFuncs[dictMode][(int)searchMethod];
U32 offset_1 = rep[0], offset_2 = rep[1], savedOffset=0;
const int isDMS = dictMode == ZSTD_dictMatchState;
@@ -915,9 +1582,7 @@ ZSTD_compressBlock_lazy_generic(
assert(searchMax != NULL);
- DEBUGLOG(5, "ZSTD_compressBlock_lazy_generic (dictMode=%u)", (U32)dictMode);
-
- /* init */
+ DEBUGLOG(5, "ZSTD_compressBlock_lazy_generic (dictMode=%u) (searchFunc=%u)", (U32)dictMode, (U32)searchMethod);
ip += (dictAndPrefixLength == 0);
if (dictMode == ZSTD_noDict) {
U32 const curr = (U32)(ip - base);
@@ -933,6 +1598,12 @@ ZSTD_compressBlock_lazy_generic(
assert(offset_2 <= dictAndPrefixLength);
}
+ if (searchMethod == search_rowHash) {
+ ZSTD_row_fillHashCache(ms, base, rowLog,
+ MIN(ms->cParams.minMatch, 6 /* mls caps out at 6 */),
+ ms->nextToUpdate, ilimit);
+ }
+
/* Match Loop */
#if defined(__GNUC__) && defined(__x86_64__)
/* I've measured random a 5% speed loss on levels 5 & 6 (greedy) when the
@@ -1198,6 +1869,70 @@ size_t ZSTD_compressBlock_greedy_dedicatedDictSearch(
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 0, ZSTD_dedicatedDictSearch);
}
+/* Row-based matchfinder */
+size_t ZSTD_compressBlock_lazy2_row(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 2, ZSTD_noDict);
+}
+
+size_t ZSTD_compressBlock_lazy_row(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 1, ZSTD_noDict);
+}
+
+size_t ZSTD_compressBlock_greedy_row(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 0, ZSTD_noDict);
+}
+
+size_t ZSTD_compressBlock_lazy2_dictMatchState_row(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 2, ZSTD_dictMatchState);
+}
+
+size_t ZSTD_compressBlock_lazy_dictMatchState_row(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 1, ZSTD_dictMatchState);
+}
+
+size_t ZSTD_compressBlock_greedy_dictMatchState_row(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 0, ZSTD_dictMatchState);
+}
+
+
+size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch_row(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 2, ZSTD_dedicatedDictSearch);
+}
+
+size_t ZSTD_compressBlock_lazy_dedicatedDictSearch_row(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 1, ZSTD_dedicatedDictSearch);
+}
+
+size_t ZSTD_compressBlock_greedy_dedicatedDictSearch_row(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 0, ZSTD_dedicatedDictSearch);
+}
FORCE_INLINE_TEMPLATE
size_t ZSTD_compressBlock_lazy_extDict_generic(
@@ -1210,7 +1945,7 @@ size_t ZSTD_compressBlock_lazy_extDict_generic(
const BYTE* ip = istart;
const BYTE* anchor = istart;
const BYTE* const iend = istart + srcSize;
- const BYTE* const ilimit = iend - 8;
+ const BYTE* const ilimit = searchMethod == search_rowHash ? iend - 8 - ZSTD_ROW_HASH_CACHE_SIZE : iend - 8;
const BYTE* const base = ms->window.base;
const U32 dictLimit = ms->window.dictLimit;
const BYTE* const prefixStart = base + dictLimit;
@@ -1218,18 +1953,28 @@ size_t ZSTD_compressBlock_lazy_extDict_generic(
const BYTE* const dictEnd = dictBase + dictLimit;
const BYTE* const dictStart = dictBase + ms->window.lowLimit;
const U32 windowLog = ms->cParams.windowLog;
+ const U32 rowLog = ms->cParams.searchLog < 5 ? 4 : 5;
typedef size_t (*searchMax_f)(
ZSTD_matchState_t* ms,
const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr);
- searchMax_f searchMax = searchMethod==search_binaryTree ? ZSTD_BtFindBestMatch_extDict_selectMLS : ZSTD_HcFindBestMatch_extDict_selectMLS;
-
+ const searchMax_f searchFuncs[3] = {
+ ZSTD_HcFindBestMatch_extDict_selectMLS,
+ ZSTD_BtFindBestMatch_extDict_selectMLS,
+ ZSTD_RowFindBestMatch_extDict_selectRowLog
+ };
+ searchMax_f searchMax = searchFuncs[(int)searchMethod];
U32 offset_1 = rep[0], offset_2 = rep[1];
- DEBUGLOG(5, "ZSTD_compressBlock_lazy_extDict_generic");
+ DEBUGLOG(5, "ZSTD_compressBlock_lazy_extDict_generic (searchFunc=%u)", (U32)searchMethod);
/* init */
ip += (ip == prefixStart);
+ if (searchMethod == search_rowHash) {
+ ZSTD_row_fillHashCache(ms, base, rowLog,
+ MIN(ms->cParams.minMatch, 6 /* mls caps out at 6 */),
+ ms->nextToUpdate, ilimit);
+ }
/* Match Loop */
#if defined(__GNUC__) && defined(__x86_64__)
@@ -1249,7 +1994,8 @@ size_t ZSTD_compressBlock_lazy_extDict_generic(
const U32 repIndex = (U32)(curr+1 - offset_1);
const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
const BYTE* const repMatch = repBase + repIndex;
- if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > windowLow)) /* intentional overflow */
+ if ( ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
+ & (offset_1 < curr+1 - windowLow) ) /* note: we are searching at curr+1 */
if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
/* repcode detected we should take it */
const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
@@ -1280,7 +2026,8 @@ size_t ZSTD_compressBlock_lazy_extDict_generic(
const U32 repIndex = (U32)(curr - offset_1);
const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
const BYTE* const repMatch = repBase + repIndex;
- if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > windowLow)) /* intentional overflow */
+ if ( ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow : do not test positions overlapping 2 memory segments */
+ & (offset_1 < curr - windowLow) ) /* equivalent to `curr > repIndex >= windowLow` */
if (MEM_read32(ip) == MEM_read32(repMatch)) {
/* repcode detected */
const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
@@ -1311,7 +2058,8 @@ size_t ZSTD_compressBlock_lazy_extDict_generic(
const U32 repIndex = (U32)(curr - offset_1);
const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
const BYTE* const repMatch = repBase + repIndex;
- if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > windowLow)) /* intentional overflow */
+ if ( ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow : do not test positions overlapping 2 memory segments */
+ & (offset_1 < curr - windowLow) ) /* equivalent to `curr > repIndex >= windowLow` */
if (MEM_read32(ip) == MEM_read32(repMatch)) {
/* repcode detected */
const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
@@ -1357,7 +2105,8 @@ _storeSequence:
const U32 repIndex = repCurrent - offset_2;
const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
const BYTE* const repMatch = repBase + repIndex;
- if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > windowLow)) /* intentional overflow */
+ if ( ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow : do not test positions overlapping 2 memory segments */
+ & (offset_2 < repCurrent - windowLow) ) /* equivalent to `curr > repIndex >= windowLow` */
if (MEM_read32(ip) == MEM_read32(repMatch)) {
/* repcode detected we should take it */
const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
@@ -1410,3 +2159,26 @@ size_t ZSTD_compressBlock_btlazy2_extDict(
{
return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_binaryTree, 2);
}
+
+size_t ZSTD_compressBlock_greedy_extDict_row(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+{
+ return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 0);
+}
+
+size_t ZSTD_compressBlock_lazy_extDict_row(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+
+{
+ return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 1);
+}
+
+size_t ZSTD_compressBlock_lazy2_extDict_row(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize)
+
+{
+ return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 2);
+}
diff --git a/thirdparty/zstd/compress/zstd_lazy.h b/thirdparty/zstd/compress/zstd_lazy.h
index d0214d5e73..150f7b390b 100644
--- a/thirdparty/zstd/compress/zstd_lazy.h
+++ b/thirdparty/zstd/compress/zstd_lazy.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
@@ -26,6 +26,7 @@ extern "C" {
#define ZSTD_LAZY_DDSS_BUCKET_LOG 2
U32 ZSTD_insertAndFindFirstIndex(ZSTD_matchState_t* ms, const BYTE* ip);
+void ZSTD_row_update(ZSTD_matchState_t* const ms, const BYTE* ip);
void ZSTD_dedicatedDictSearch_lazy_loadDictionary(ZSTD_matchState_t* ms, const BYTE* const ip);
@@ -43,6 +44,15 @@ size_t ZSTD_compressBlock_lazy(
size_t ZSTD_compressBlock_greedy(
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy2_row(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy_row(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_greedy_row(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
size_t ZSTD_compressBlock_btlazy2_dictMatchState(
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
@@ -56,6 +66,15 @@ size_t ZSTD_compressBlock_lazy_dictMatchState(
size_t ZSTD_compressBlock_greedy_dictMatchState(
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy2_dictMatchState_row(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy_dictMatchState_row(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_greedy_dictMatchState_row(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch(
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
@@ -66,6 +85,15 @@ size_t ZSTD_compressBlock_lazy_dedicatedDictSearch(
size_t ZSTD_compressBlock_greedy_dedicatedDictSearch(
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch_row(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy_dedicatedDictSearch_row(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_greedy_dedicatedDictSearch_row(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
size_t ZSTD_compressBlock_greedy_extDict(
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
@@ -76,9 +104,19 @@ size_t ZSTD_compressBlock_lazy_extDict(
size_t ZSTD_compressBlock_lazy2_extDict(
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_greedy_extDict_row(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy_extDict_row(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy2_extDict_row(
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ void const* src, size_t srcSize);
size_t ZSTD_compressBlock_btlazy2_extDict(
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
void const* src, size_t srcSize);
+
#if defined (__cplusplus)
}
diff --git a/thirdparty/zstd/compress/zstd_ldm.c b/thirdparty/zstd/compress/zstd_ldm.c
index 3f3d7c46ab..fa4ebeabd7 100644
--- a/thirdparty/zstd/compress/zstd_ldm.c
+++ b/thirdparty/zstd/compress/zstd_ldm.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
@@ -11,13 +11,126 @@
#include "zstd_ldm.h"
#include "../common/debug.h"
+#include "../common/xxhash.h"
#include "zstd_fast.h" /* ZSTD_fillHashTable() */
#include "zstd_double_fast.h" /* ZSTD_fillDoubleHashTable() */
+#include "zstd_ldm_geartab.h"
#define LDM_BUCKET_SIZE_LOG 3
#define LDM_MIN_MATCH_LENGTH 64
#define LDM_HASH_RLOG 7
-#define LDM_HASH_CHAR_OFFSET 10
+
+typedef struct {
+ U64 rolling;
+ U64 stopMask;
+} ldmRollingHashState_t;
+
+/** ZSTD_ldm_gear_init():
+ *
+ * Initializes the rolling hash state such that it will honor the
+ * settings in params. */
+static void ZSTD_ldm_gear_init(ldmRollingHashState_t* state, ldmParams_t const* params)
+{
+ unsigned maxBitsInMask = MIN(params->minMatchLength, 64);
+ unsigned hashRateLog = params->hashRateLog;
+
+ state->rolling = ~(U32)0;
+
+ /* The choice of the splitting criterion is subject to two conditions:
+ * 1. it has to trigger on average every 2^(hashRateLog) bytes;
+ * 2. ideally, it has to depend on a window of minMatchLength bytes.
+ *
+ * In the gear hash algorithm, bit n depends on the last n bytes;
+ * so in order to obtain a good quality splitting criterion it is
+ * preferable to use bits with high weight.
+ *
+ * To match condition 1 we use a mask with hashRateLog bits set
+ * and, because of the previous remark, we make sure these bits
+ * have the highest possible weight while still respecting
+ * condition 2.
+ */
+ if (hashRateLog > 0 && hashRateLog <= maxBitsInMask) {
+ state->stopMask = (((U64)1 << hashRateLog) - 1) << (maxBitsInMask - hashRateLog);
+ } else {
+ /* In this degenerate case we simply honor the hash rate. */
+ state->stopMask = ((U64)1 << hashRateLog) - 1;
+ }
+}
+
+/** ZSTD_ldm_gear_reset()
+ * Feeds [data, data + minMatchLength) into the hash without registering any
+ * splits. This effectively resets the hash state. This is used when skipping
+ * over data, either at the beginning of a block, or skipping sections.
+ */
+static void ZSTD_ldm_gear_reset(ldmRollingHashState_t* state,
+ BYTE const* data, size_t minMatchLength)
+{
+ U64 hash = state->rolling;
+ size_t n = 0;
+
+#define GEAR_ITER_ONCE() do { \
+ hash = (hash << 1) + ZSTD_ldm_gearTab[data[n] & 0xff]; \
+ n += 1; \
+ } while (0)
+ while (n + 3 < minMatchLength) {
+ GEAR_ITER_ONCE();
+ GEAR_ITER_ONCE();
+ GEAR_ITER_ONCE();
+ GEAR_ITER_ONCE();
+ }
+ while (n < minMatchLength) {
+ GEAR_ITER_ONCE();
+ }
+#undef GEAR_ITER_ONCE
+}
+
+/** ZSTD_ldm_gear_feed():
+ *
+ * Registers in the splits array all the split points found in the first
+ * size bytes following the data pointer. This function terminates when
+ * either all the data has been processed or LDM_BATCH_SIZE splits are
+ * present in the splits array.
+ *
+ * Precondition: The splits array must not be full.
+ * Returns: The number of bytes processed. */
+static size_t ZSTD_ldm_gear_feed(ldmRollingHashState_t* state,
+ BYTE const* data, size_t size,
+ size_t* splits, unsigned* numSplits)
+{
+ size_t n;
+ U64 hash, mask;
+
+ hash = state->rolling;
+ mask = state->stopMask;
+ n = 0;
+
+#define GEAR_ITER_ONCE() do { \
+ hash = (hash << 1) + ZSTD_ldm_gearTab[data[n] & 0xff]; \
+ n += 1; \
+ if (UNLIKELY((hash & mask) == 0)) { \
+ splits[*numSplits] = n; \
+ *numSplits += 1; \
+ if (*numSplits == LDM_BATCH_SIZE) \
+ goto done; \
+ } \
+ } while (0)
+
+ while (n + 3 < size) {
+ GEAR_ITER_ONCE();
+ GEAR_ITER_ONCE();
+ GEAR_ITER_ONCE();
+ GEAR_ITER_ONCE();
+ }
+ while (n < size) {
+ GEAR_ITER_ONCE();
+ }
+
+#undef GEAR_ITER_ONCE
+
+done:
+ state->rolling = hash;
+ return n;
+}
void ZSTD_ldm_adjustParameters(ldmParams_t* params,
ZSTD_compressionParameters const* cParams)
@@ -54,41 +167,6 @@ size_t ZSTD_ldm_getMaxNbSeq(ldmParams_t params, size_t maxChunkSize)
return params.enableLdm ? (maxChunkSize / params.minMatchLength) : 0;
}
-/** ZSTD_ldm_getSmallHash() :
- * numBits should be <= 32
- * If numBits==0, returns 0.
- * @return : the most significant numBits of value. */
-static U32 ZSTD_ldm_getSmallHash(U64 value, U32 numBits)
-{
- assert(numBits <= 32);
- return numBits == 0 ? 0 : (U32)(value >> (64 - numBits));
-}
-
-/** ZSTD_ldm_getChecksum() :
- * numBitsToDiscard should be <= 32
- * @return : the next most significant 32 bits after numBitsToDiscard */
-static U32 ZSTD_ldm_getChecksum(U64 hash, U32 numBitsToDiscard)
-{
- assert(numBitsToDiscard <= 32);
- return (hash >> (64 - 32 - numBitsToDiscard)) & 0xFFFFFFFF;
-}
-
-/** ZSTD_ldm_getTag() ;
- * Given the hash, returns the most significant numTagBits bits
- * after (32 + hbits) bits.
- *
- * If there are not enough bits remaining, return the last
- * numTagBits bits. */
-static U32 ZSTD_ldm_getTag(U64 hash, U32 hbits, U32 numTagBits)
-{
- assert(numTagBits < 32 && hbits <= 32);
- if (32 - hbits < numTagBits) {
- return hash & (((U32)1 << numTagBits) - 1);
- } else {
- return (hash >> (32 - hbits - numTagBits)) & (((U32)1 << numTagBits) - 1);
- }
-}
-
/** ZSTD_ldm_getBucket() :
* Returns a pointer to the start of the bucket associated with hash. */
static ldmEntry_t* ZSTD_ldm_getBucket(
@@ -103,38 +181,12 @@ static void ZSTD_ldm_insertEntry(ldmState_t* ldmState,
size_t const hash, const ldmEntry_t entry,
ldmParams_t const ldmParams)
{
- BYTE* const bucketOffsets = ldmState->bucketOffsets;
- *(ZSTD_ldm_getBucket(ldmState, hash, ldmParams) + bucketOffsets[hash]) = entry;
- bucketOffsets[hash]++;
- bucketOffsets[hash] &= ((U32)1 << ldmParams.bucketSizeLog) - 1;
-}
+ BYTE* const pOffset = ldmState->bucketOffsets + hash;
+ unsigned const offset = *pOffset;
+
+ *(ZSTD_ldm_getBucket(ldmState, hash, ldmParams) + offset) = entry;
+ *pOffset = (BYTE)((offset + 1) & ((1u << ldmParams.bucketSizeLog) - 1));
-/** ZSTD_ldm_makeEntryAndInsertByTag() :
- *
- * Gets the small hash, checksum, and tag from the rollingHash.
- *
- * If the tag matches (1 << ldmParams.hashRateLog)-1, then
- * creates an ldmEntry from the offset, and inserts it into the hash table.
- *
- * hBits is the length of the small hash, which is the most significant hBits
- * of rollingHash. The checksum is the next 32 most significant bits, followed
- * by ldmParams.hashRateLog bits that make up the tag. */
-static void ZSTD_ldm_makeEntryAndInsertByTag(ldmState_t* ldmState,
- U64 const rollingHash,
- U32 const hBits,
- U32 const offset,
- ldmParams_t const ldmParams)
-{
- U32 const tag = ZSTD_ldm_getTag(rollingHash, hBits, ldmParams.hashRateLog);
- U32 const tagMask = ((U32)1 << ldmParams.hashRateLog) - 1;
- if (tag == tagMask) {
- U32 const hash = ZSTD_ldm_getSmallHash(rollingHash, hBits);
- U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits);
- ldmEntry_t entry;
- entry.offset = offset;
- entry.checksum = checksum;
- ZSTD_ldm_insertEntry(ldmState, hash, entry, ldmParams);
- }
}
/** ZSTD_ldm_countBackwardsMatch() :
@@ -212,43 +264,42 @@ static size_t ZSTD_ldm_fillFastTables(ZSTD_matchState_t* ms,
return 0;
}
-/** ZSTD_ldm_fillLdmHashTable() :
- *
- * Fills hashTable from (lastHashed + 1) to iend (non-inclusive).
- * lastHash is the rolling hash that corresponds to lastHashed.
- *
- * Returns the rolling hash corresponding to position iend-1. */
-static U64 ZSTD_ldm_fillLdmHashTable(ldmState_t* state,
- U64 lastHash, const BYTE* lastHashed,
- const BYTE* iend, const BYTE* base,
- U32 hBits, ldmParams_t const ldmParams)
-{
- U64 rollingHash = lastHash;
- const BYTE* cur = lastHashed + 1;
-
- while (cur < iend) {
- rollingHash = ZSTD_rollingHash_rotate(rollingHash, cur[-1],
- cur[ldmParams.minMatchLength-1],
- state->hashPower);
- ZSTD_ldm_makeEntryAndInsertByTag(state,
- rollingHash, hBits,
- (U32)(cur - base), ldmParams);
- ++cur;
- }
- return rollingHash;
-}
-
void ZSTD_ldm_fillHashTable(
- ldmState_t* state, const BYTE* ip,
+ ldmState_t* ldmState, const BYTE* ip,
const BYTE* iend, ldmParams_t const* params)
{
+ U32 const minMatchLength = params->minMatchLength;
+ U32 const hBits = params->hashLog - params->bucketSizeLog;
+ BYTE const* const base = ldmState->window.base;
+ BYTE const* const istart = ip;
+ ldmRollingHashState_t hashState;
+ size_t* const splits = ldmState->splitIndices;
+ unsigned numSplits;
+
DEBUGLOG(5, "ZSTD_ldm_fillHashTable");
- if ((size_t)(iend - ip) >= params->minMatchLength) {
- U64 startingHash = ZSTD_rollingHash_compute(ip, params->minMatchLength);
- ZSTD_ldm_fillLdmHashTable(
- state, startingHash, ip, iend - params->minMatchLength, state->window.base,
- params->hashLog - params->bucketSizeLog,
- *params);
+
+ ZSTD_ldm_gear_init(&hashState, params);
+ while (ip < iend) {
+ size_t hashed;
+ unsigned n;
+
+ numSplits = 0;
+ hashed = ZSTD_ldm_gear_feed(&hashState, ip, iend - ip, splits, &numSplits);
+
+ for (n = 0; n < numSplits; n++) {
+ if (ip + splits[n] >= istart + minMatchLength) {
+ BYTE const* const split = ip + splits[n] - minMatchLength;
+ U64 const xxhash = XXH64(split, minMatchLength, 0);
+ U32 const hash = (U32)(xxhash & (((U32)1 << hBits) - 1));
+ ldmEntry_t entry;
+
+ entry.offset = (U32)(split - base);
+ entry.checksum = (U32)(xxhash >> 32);
+ ZSTD_ldm_insertEntry(ldmState, hash, entry, *params);
+ }
+ }
+
+ ip += hashed;
}
}
@@ -274,11 +325,8 @@ static size_t ZSTD_ldm_generateSequences_internal(
/* LDM parameters */
int const extDict = ZSTD_window_hasExtDict(ldmState->window);
U32 const minMatchLength = params->minMatchLength;
- U64 const hashPower = ldmState->hashPower;
+ U32 const entsPerBucket = 1U << params->bucketSizeLog;
U32 const hBits = params->hashLog - params->bucketSizeLog;
- U32 const ldmBucketSize = 1U << params->bucketSizeLog;
- U32 const hashRateLog = params->hashRateLog;
- U32 const ldmTagMask = (1U << params->hashRateLog) - 1;
/* Prefix and extDict parameters */
U32 const dictLimit = ldmState->window.dictLimit;
U32 const lowestIndex = extDict ? ldmState->window.lowLimit : dictLimit;
@@ -290,45 +338,69 @@ static size_t ZSTD_ldm_generateSequences_internal(
/* Input bounds */
BYTE const* const istart = (BYTE const*)src;
BYTE const* const iend = istart + srcSize;
- BYTE const* const ilimit = iend - MAX(minMatchLength, HASH_READ_SIZE);
+ BYTE const* const ilimit = iend - HASH_READ_SIZE;
/* Input positions */
BYTE const* anchor = istart;
BYTE const* ip = istart;
- /* Rolling hash */
- BYTE const* lastHashed = NULL;
- U64 rollingHash = 0;
-
- while (ip <= ilimit) {
- size_t mLength;
- U32 const curr = (U32)(ip - base);
- size_t forwardMatchLength = 0, backwardMatchLength = 0;
- ldmEntry_t* bestEntry = NULL;
- if (ip != istart) {
- rollingHash = ZSTD_rollingHash_rotate(rollingHash, lastHashed[0],
- lastHashed[minMatchLength],
- hashPower);
- } else {
- rollingHash = ZSTD_rollingHash_compute(ip, minMatchLength);
+ /* Rolling hash state */
+ ldmRollingHashState_t hashState;
+ /* Arrays for staged-processing */
+ size_t* const splits = ldmState->splitIndices;
+ ldmMatchCandidate_t* const candidates = ldmState->matchCandidates;
+ unsigned numSplits;
+
+ if (srcSize < minMatchLength)
+ return iend - anchor;
+
+ /* Initialize the rolling hash state with the first minMatchLength bytes */
+ ZSTD_ldm_gear_init(&hashState, params);
+ ZSTD_ldm_gear_reset(&hashState, ip, minMatchLength);
+ ip += minMatchLength;
+
+ while (ip < ilimit) {
+ size_t hashed;
+ unsigned n;
+
+ numSplits = 0;
+ hashed = ZSTD_ldm_gear_feed(&hashState, ip, ilimit - ip,
+ splits, &numSplits);
+
+ for (n = 0; n < numSplits; n++) {
+ BYTE const* const split = ip + splits[n] - minMatchLength;
+ U64 const xxhash = XXH64(split, minMatchLength, 0);
+ U32 const hash = (U32)(xxhash & (((U32)1 << hBits) - 1));
+
+ candidates[n].split = split;
+ candidates[n].hash = hash;
+ candidates[n].checksum = (U32)(xxhash >> 32);
+ candidates[n].bucket = ZSTD_ldm_getBucket(ldmState, hash, *params);
+ PREFETCH_L1(candidates[n].bucket);
}
- lastHashed = ip;
- /* Do not insert and do not look for a match */
- if (ZSTD_ldm_getTag(rollingHash, hBits, hashRateLog) != ldmTagMask) {
- ip++;
- continue;
- }
+ for (n = 0; n < numSplits; n++) {
+ size_t forwardMatchLength = 0, backwardMatchLength = 0,
+ bestMatchLength = 0, mLength;
+ U32 offset;
+ BYTE const* const split = candidates[n].split;
+ U32 const checksum = candidates[n].checksum;
+ U32 const hash = candidates[n].hash;
+ ldmEntry_t* const bucket = candidates[n].bucket;
+ ldmEntry_t const* cur;
+ ldmEntry_t const* bestEntry = NULL;
+ ldmEntry_t newEntry;
+
+ newEntry.offset = (U32)(split - base);
+ newEntry.checksum = checksum;
+
+ /* If a split point would generate a sequence overlapping with
+ * the previous one, we merely register it in the hash table and
+ * move on */
+ if (split < anchor) {
+ ZSTD_ldm_insertEntry(ldmState, hash, newEntry, *params);
+ continue;
+ }
- /* Get the best entry and compute the match lengths */
- {
- ldmEntry_t* const bucket =
- ZSTD_ldm_getBucket(ldmState,
- ZSTD_ldm_getSmallHash(rollingHash, hBits),
- *params);
- ldmEntry_t* cur;
- size_t bestMatchLength = 0;
- U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits);
-
- for (cur = bucket; cur < bucket + ldmBucketSize; ++cur) {
+ for (cur = bucket; cur < bucket + entsPerBucket; cur++) {
size_t curForwardMatchLength, curBackwardMatchLength,
curTotalMatchLength;
if (cur->checksum != checksum || cur->offset <= lowestIndex) {
@@ -342,31 +414,23 @@ static size_t ZSTD_ldm_generateSequences_internal(
cur->offset < dictLimit ? dictEnd : iend;
BYTE const* const lowMatchPtr =
cur->offset < dictLimit ? dictStart : lowPrefixPtr;
-
- curForwardMatchLength = ZSTD_count_2segments(
- ip, pMatch, iend,
- matchEnd, lowPrefixPtr);
+ curForwardMatchLength =
+ ZSTD_count_2segments(split, pMatch, iend, matchEnd, lowPrefixPtr);
if (curForwardMatchLength < minMatchLength) {
continue;
}
- curBackwardMatchLength =
- ZSTD_ldm_countBackwardsMatch_2segments(ip, anchor,
- pMatch, lowMatchPtr,
- dictStart, dictEnd);
- curTotalMatchLength = curForwardMatchLength +
- curBackwardMatchLength;
+ curBackwardMatchLength = ZSTD_ldm_countBackwardsMatch_2segments(
+ split, anchor, pMatch, lowMatchPtr, dictStart, dictEnd);
} else { /* !extDict */
BYTE const* const pMatch = base + cur->offset;
- curForwardMatchLength = ZSTD_count(ip, pMatch, iend);
+ curForwardMatchLength = ZSTD_count(split, pMatch, iend);
if (curForwardMatchLength < minMatchLength) {
continue;
}
curBackwardMatchLength =
- ZSTD_ldm_countBackwardsMatch(ip, anchor, pMatch,
- lowPrefixPtr);
- curTotalMatchLength = curForwardMatchLength +
- curBackwardMatchLength;
+ ZSTD_ldm_countBackwardsMatch(split, anchor, pMatch, lowPrefixPtr);
}
+ curTotalMatchLength = curForwardMatchLength + curBackwardMatchLength;
if (curTotalMatchLength > bestMatchLength) {
bestMatchLength = curTotalMatchLength;
@@ -375,57 +439,54 @@ static size_t ZSTD_ldm_generateSequences_internal(
bestEntry = cur;
}
}
- }
-
- /* No match found -- continue searching */
- if (bestEntry == NULL) {
- ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash,
- hBits, curr,
- *params);
- ip++;
- continue;
- }
- /* Match found */
- mLength = forwardMatchLength + backwardMatchLength;
- ip -= backwardMatchLength;
+ /* No match found -- insert an entry into the hash table
+ * and process the next candidate match */
+ if (bestEntry == NULL) {
+ ZSTD_ldm_insertEntry(ldmState, hash, newEntry, *params);
+ continue;
+ }
- {
- /* Store the sequence:
- * ip = curr - backwardMatchLength
- * The match is at (bestEntry->offset - backwardMatchLength)
- */
- U32 const matchIndex = bestEntry->offset;
- U32 const offset = curr - matchIndex;
- rawSeq* const seq = rawSeqStore->seq + rawSeqStore->size;
-
- /* Out of sequence storage */
- if (rawSeqStore->size == rawSeqStore->capacity)
- return ERROR(dstSize_tooSmall);
- seq->litLength = (U32)(ip - anchor);
- seq->matchLength = (U32)mLength;
- seq->offset = offset;
- rawSeqStore->size++;
- }
+ /* Match found */
+ offset = (U32)(split - base) - bestEntry->offset;
+ mLength = forwardMatchLength + backwardMatchLength;
+ {
+ rawSeq* const seq = rawSeqStore->seq + rawSeqStore->size;
+
+ /* Out of sequence storage */
+ if (rawSeqStore->size == rawSeqStore->capacity)
+ return ERROR(dstSize_tooSmall);
+ seq->litLength = (U32)(split - backwardMatchLength - anchor);
+ seq->matchLength = (U32)mLength;
+ seq->offset = offset;
+ rawSeqStore->size++;
+ }
- /* Insert the current entry into the hash table */
- ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits,
- (U32)(lastHashed - base),
- *params);
+ /* Insert the current entry into the hash table --- it must be
+ * done after the previous block to avoid clobbering bestEntry */
+ ZSTD_ldm_insertEntry(ldmState, hash, newEntry, *params);
- assert(ip + backwardMatchLength == lastHashed);
+ anchor = split + forwardMatchLength;
- /* Fill the hash table from lastHashed+1 to ip+mLength*/
- /* Heuristic: don't need to fill the entire table at end of block */
- if (ip + mLength <= ilimit) {
- rollingHash = ZSTD_ldm_fillLdmHashTable(
- ldmState, rollingHash, lastHashed,
- ip + mLength, base, hBits, *params);
- lastHashed = ip + mLength - 1;
+ /* If we find a match that ends after the data that we've hashed
+ * then we have a repeating, overlapping, pattern. E.g. all zeros.
+ * If one repetition of the pattern matches our `stopMask` then all
+ * repetitions will. We don't need to insert them all into out table,
+ * only the first one. So skip over overlapping matches.
+ * This is a major speed boost (20x) for compressing a single byte
+ * repeated, when that byte ends up in the table.
+ */
+ if (anchor > ip + hashed) {
+ ZSTD_ldm_gear_reset(&hashState, anchor - minMatchLength, minMatchLength);
+ /* Continue the outter loop at anchor (ip + hashed == anchor). */
+ ip = anchor - hashed;
+ break;
+ }
}
- ip += mLength;
- anchor = ip;
+
+ ip += hashed;
}
+
return iend - anchor;
}
@@ -474,7 +535,7 @@ size_t ZSTD_ldm_generateSequences(
assert(chunkStart < iend);
/* 1. Perform overflow correction if necessary. */
- if (ZSTD_window_needOverflowCorrection(ldmState->window, chunkEnd)) {
+ if (ZSTD_window_needOverflowCorrection(ldmState->window, 0, maxDist, ldmState->loadedDictEnd, chunkStart, chunkEnd)) {
U32 const ldmHSize = 1U << params->hashLog;
U32 const correction = ZSTD_window_correctOverflow(
&ldmState->window, /* cycleLog */ 0, maxDist, chunkStart);
@@ -596,12 +657,13 @@ void ZSTD_ldm_skipRawSeqStoreBytes(rawSeqStore_t* rawSeqStore, size_t nbBytes) {
size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_useRowMatchFinderMode_e useRowMatchFinder,
void const* src, size_t srcSize)
{
const ZSTD_compressionParameters* const cParams = &ms->cParams;
unsigned const minMatch = cParams->minMatch;
ZSTD_blockCompressor const blockCompressor =
- ZSTD_selectBlockCompressor(cParams->strategy, ZSTD_matchState_dictMode(ms));
+ ZSTD_selectBlockCompressor(cParams->strategy, useRowMatchFinder, ZSTD_matchState_dictMode(ms));
/* Input bounds */
BYTE const* const istart = (BYTE const*)src;
BYTE const* const iend = istart + srcSize;
@@ -620,7 +682,7 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
assert(rawSeqStore->pos <= rawSeqStore->size);
assert(rawSeqStore->size <= rawSeqStore->capacity);
- /* Loop through each sequence and apply the block compressor to the lits */
+ /* Loop through each sequence and apply the block compressor to the literals */
while (rawSeqStore->pos < rawSeqStore->size && ip < iend) {
/* maybeSplitSequence updates rawSeqStore->pos */
rawSeq const sequence = maybeSplitSequence(rawSeqStore,
diff --git a/thirdparty/zstd/compress/zstd_ldm.h b/thirdparty/zstd/compress/zstd_ldm.h
index 6561024e4c..393466fa9f 100644
--- a/thirdparty/zstd/compress/zstd_ldm.h
+++ b/thirdparty/zstd/compress/zstd_ldm.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
@@ -66,6 +66,7 @@ size_t ZSTD_ldm_generateSequences(
*/
size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+ ZSTD_useRowMatchFinderMode_e useRowMatchFinder,
void const* src, size_t srcSize);
/**
@@ -73,7 +74,7 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
*
* Skip past `srcSize` bytes worth of sequences in `rawSeqStore`.
* Avoids emitting matches less than `minMatch` bytes.
- * Must be called for data with is not passed to ZSTD_ldm_blockCompress().
+ * Must be called for data that is not passed to ZSTD_ldm_blockCompress().
*/
void ZSTD_ldm_skipSequences(rawSeqStore_t* rawSeqStore, size_t srcSize,
U32 const minMatch);
diff --git a/thirdparty/zstd/compress/zstd_ldm_geartab.h b/thirdparty/zstd/compress/zstd_ldm_geartab.h
new file mode 100644
index 0000000000..e5c24d856b
--- /dev/null
+++ b/thirdparty/zstd/compress/zstd_ldm_geartab.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef ZSTD_LDM_GEARTAB_H
+#define ZSTD_LDM_GEARTAB_H
+
+static U64 ZSTD_ldm_gearTab[256] = {
+ 0xf5b8f72c5f77775c, 0x84935f266b7ac412, 0xb647ada9ca730ccc,
+ 0xb065bb4b114fb1de, 0x34584e7e8c3a9fd0, 0x4e97e17c6ae26b05,
+ 0x3a03d743bc99a604, 0xcecd042422c4044f, 0x76de76c58524259e,
+ 0x9c8528f65badeaca, 0x86563706e2097529, 0x2902475fa375d889,
+ 0xafb32a9739a5ebe6, 0xce2714da3883e639, 0x21eaf821722e69e,
+ 0x37b628620b628, 0x49a8d455d88caf5, 0x8556d711e6958140,
+ 0x4f7ae74fc605c1f, 0x829f0c3468bd3a20, 0x4ffdc885c625179e,
+ 0x8473de048a3daf1b, 0x51008822b05646b2, 0x69d75d12b2d1cc5f,
+ 0x8c9d4a19159154bc, 0xc3cc10f4abbd4003, 0xd06ddc1cecb97391,
+ 0xbe48e6e7ed80302e, 0x3481db31cee03547, 0xacc3f67cdaa1d210,
+ 0x65cb771d8c7f96cc, 0x8eb27177055723dd, 0xc789950d44cd94be,
+ 0x934feadc3700b12b, 0x5e485f11edbdf182, 0x1e2e2a46fd64767a,
+ 0x2969ca71d82efa7c, 0x9d46e9935ebbba2e, 0xe056b67e05e6822b,
+ 0x94d73f55739d03a0, 0xcd7010bdb69b5a03, 0x455ef9fcd79b82f4,
+ 0x869cb54a8749c161, 0x38d1a4fa6185d225, 0xb475166f94bbe9bb,
+ 0xa4143548720959f1, 0x7aed4780ba6b26ba, 0xd0ce264439e02312,
+ 0x84366d746078d508, 0xa8ce973c72ed17be, 0x21c323a29a430b01,
+ 0x9962d617e3af80ee, 0xab0ce91d9c8cf75b, 0x530e8ee6d19a4dbc,
+ 0x2ef68c0cf53f5d72, 0xc03a681640a85506, 0x496e4e9f9c310967,
+ 0x78580472b59b14a0, 0x273824c23b388577, 0x66bf923ad45cb553,
+ 0x47ae1a5a2492ba86, 0x35e304569e229659, 0x4765182a46870b6f,
+ 0x6cbab625e9099412, 0xddac9a2e598522c1, 0x7172086e666624f2,
+ 0xdf5003ca503b7837, 0x88c0c1db78563d09, 0x58d51865acfc289d,
+ 0x177671aec65224f1, 0xfb79d8a241e967d7, 0x2be1e101cad9a49a,
+ 0x6625682f6e29186b, 0x399553457ac06e50, 0x35dffb4c23abb74,
+ 0x429db2591f54aade, 0xc52802a8037d1009, 0x6acb27381f0b25f3,
+ 0xf45e2551ee4f823b, 0x8b0ea2d99580c2f7, 0x3bed519cbcb4e1e1,
+ 0xff452823dbb010a, 0x9d42ed614f3dd267, 0x5b9313c06257c57b,
+ 0xa114b8008b5e1442, 0xc1fe311c11c13d4b, 0x66e8763ea34c5568,
+ 0x8b982af1c262f05d, 0xee8876faaa75fbb7, 0x8a62a4d0d172bb2a,
+ 0xc13d94a3b7449a97, 0x6dbbba9dc15d037c, 0xc786101f1d92e0f1,
+ 0xd78681a907a0b79b, 0xf61aaf2962c9abb9, 0x2cfd16fcd3cb7ad9,
+ 0x868c5b6744624d21, 0x25e650899c74ddd7, 0xba042af4a7c37463,
+ 0x4eb1a539465a3eca, 0xbe09dbf03b05d5ca, 0x774e5a362b5472ba,
+ 0x47a1221229d183cd, 0x504b0ca18ef5a2df, 0xdffbdfbde2456eb9,
+ 0x46cd2b2fbee34634, 0xf2aef8fe819d98c3, 0x357f5276d4599d61,
+ 0x24a5483879c453e3, 0x88026889192b4b9, 0x28da96671782dbec,
+ 0x4ef37c40588e9aaa, 0x8837b90651bc9fb3, 0xc164f741d3f0e5d6,
+ 0xbc135a0a704b70ba, 0x69cd868f7622ada, 0xbc37ba89e0b9c0ab,
+ 0x47c14a01323552f6, 0x4f00794bacee98bb, 0x7107de7d637a69d5,
+ 0x88af793bb6f2255e, 0xf3c6466b8799b598, 0xc288c616aa7f3b59,
+ 0x81ca63cf42fca3fd, 0x88d85ace36a2674b, 0xd056bd3792389e7,
+ 0xe55c396c4e9dd32d, 0xbefb504571e6c0a6, 0x96ab32115e91e8cc,
+ 0xbf8acb18de8f38d1, 0x66dae58801672606, 0x833b6017872317fb,
+ 0xb87c16f2d1c92864, 0xdb766a74e58b669c, 0x89659f85c61417be,
+ 0xc8daad856011ea0c, 0x76a4b565b6fe7eae, 0xa469d085f6237312,
+ 0xaaf0365683a3e96c, 0x4dbb746f8424f7b8, 0x638755af4e4acc1,
+ 0x3d7807f5bde64486, 0x17be6d8f5bbb7639, 0x903f0cd44dc35dc,
+ 0x67b672eafdf1196c, 0xa676ff93ed4c82f1, 0x521d1004c5053d9d,
+ 0x37ba9ad09ccc9202, 0x84e54d297aacfb51, 0xa0b4b776a143445,
+ 0x820d471e20b348e, 0x1874383cb83d46dc, 0x97edeec7a1efe11c,
+ 0xb330e50b1bdc42aa, 0x1dd91955ce70e032, 0xa514cdb88f2939d5,
+ 0x2791233fd90db9d3, 0x7b670a4cc50f7a9b, 0x77c07d2a05c6dfa5,
+ 0xe3778b6646d0a6fa, 0xb39c8eda47b56749, 0x933ed448addbef28,
+ 0xaf846af6ab7d0bf4, 0xe5af208eb666e49, 0x5e6622f73534cd6a,
+ 0x297daeca42ef5b6e, 0x862daef3d35539a6, 0xe68722498f8e1ea9,
+ 0x981c53093dc0d572, 0xfa09b0bfbf86fbf5, 0x30b1e96166219f15,
+ 0x70e7d466bdc4fb83, 0x5a66736e35f2a8e9, 0xcddb59d2b7c1baef,
+ 0xd6c7d247d26d8996, 0xea4e39eac8de1ba3, 0x539c8bb19fa3aff2,
+ 0x9f90e4c5fd508d8, 0xa34e5956fbaf3385, 0x2e2f8e151d3ef375,
+ 0x173691e9b83faec1, 0xb85a8d56bf016379, 0x8382381267408ae3,
+ 0xb90f901bbdc0096d, 0x7c6ad32933bcec65, 0x76bb5e2f2c8ad595,
+ 0x390f851a6cf46d28, 0xc3e6064da1c2da72, 0xc52a0c101cfa5389,
+ 0xd78eaf84a3fbc530, 0x3781b9e2288b997e, 0x73c2f6dea83d05c4,
+ 0x4228e364c5b5ed7, 0x9d7a3edf0da43911, 0x8edcfeda24686756,
+ 0x5e7667a7b7a9b3a1, 0x4c4f389fa143791d, 0xb08bc1023da7cddc,
+ 0x7ab4be3ae529b1cc, 0x754e6132dbe74ff9, 0x71635442a839df45,
+ 0x2f6fb1643fbe52de, 0x961e0a42cf7a8177, 0xf3b45d83d89ef2ea,
+ 0xee3de4cf4a6e3e9b, 0xcd6848542c3295e7, 0xe4cee1664c78662f,
+ 0x9947548b474c68c4, 0x25d73777a5ed8b0b, 0xc915b1d636b7fc,
+ 0x21c2ba75d9b0d2da, 0x5f6b5dcf608a64a1, 0xdcf333255ff9570c,
+ 0x633b922418ced4ee, 0xc136dde0b004b34a, 0x58cc83b05d4b2f5a,
+ 0x5eb424dda28e42d2, 0x62df47369739cd98, 0xb4e0b42485e4ce17,
+ 0x16e1f0c1f9a8d1e7, 0x8ec3916707560ebf, 0x62ba6e2df2cc9db3,
+ 0xcbf9f4ff77d83a16, 0x78d9d7d07d2bbcc4, 0xef554ce1e02c41f4,
+ 0x8d7581127eccf94d, 0xa9b53336cb3c8a05, 0x38c42c0bf45c4f91,
+ 0x640893cdf4488863, 0x80ec34bc575ea568, 0x39f324f5b48eaa40,
+ 0xe9d9ed1f8eff527f, 0x9224fc058cc5a214, 0xbaba00b04cfe7741,
+ 0x309a9f120fcf52af, 0xa558f3ec65626212, 0x424bec8b7adabe2f,
+ 0x41622513a6aea433, 0xb88da2d5324ca798, 0xd287733b245528a4,
+ 0x9a44697e6d68aec3, 0x7b1093be2f49bb28, 0x50bbec632e3d8aad,
+ 0x6cd90723e1ea8283, 0x897b9e7431b02bf3, 0x219efdcb338a7047,
+ 0x3b0311f0a27c0656, 0xdb17bf91c0db96e7, 0x8cd4fd6b4e85a5b2,
+ 0xfab071054ba6409d, 0x40d6fe831fa9dfd9, 0xaf358debad7d791e,
+ 0xeb8d0e25a65e3e58, 0xbbcbd3df14e08580, 0xcf751f27ecdab2b,
+ 0x2b4da14f2613d8f4
+};
+
+#endif /* ZSTD_LDM_GEARTAB_H */
diff --git a/thirdparty/zstd/compress/zstd_opt.c b/thirdparty/zstd/compress/zstd_opt.c
index e55c459deb..402a7e5c76 100644
--- a/thirdparty/zstd/compress/zstd_opt.c
+++ b/thirdparty/zstd/compress/zstd_opt.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Przemyslaw Skibinski, Yann Collet, Facebook, Inc.
+ * Copyright (c) Przemyslaw Skibinski, Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
diff --git a/thirdparty/zstd/compress/zstd_opt.h b/thirdparty/zstd/compress/zstd_opt.h
index 9aba8a9018..627255f53d 100644
--- a/thirdparty/zstd/compress/zstd_opt.h
+++ b/thirdparty/zstd/compress/zstd_opt.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
diff --git a/thirdparty/zstd/compress/zstdmt_compress.c b/thirdparty/zstd/compress/zstdmt_compress.c
index 50454a50b9..22aa3e1245 100644
--- a/thirdparty/zstd/compress/zstdmt_compress.c
+++ b/thirdparty/zstd/compress/zstdmt_compress.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
@@ -472,8 +472,6 @@ ZSTDMT_serialState_reset(serialState_t* serialState,
ZSTD_ldm_adjustParameters(&params.ldmParams, &params.cParams);
assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog);
assert(params.ldmParams.hashRateLog < 32);
- serialState->ldmState.hashPower =
- ZSTD_rollingHash_primePower(params.ldmParams.minMatchLength);
} else {
ZSTD_memset(&params.ldmParams, 0, sizeof(params.ldmParams));
}
@@ -486,10 +484,10 @@ ZSTDMT_serialState_reset(serialState_t* serialState,
size_t const hashSize = ((size_t)1 << hashLog) * sizeof(ldmEntry_t);
unsigned const bucketLog =
params.ldmParams.hashLog - params.ldmParams.bucketSizeLog;
- size_t const bucketSize = (size_t)1 << bucketLog;
unsigned const prevBucketLog =
serialState->params.ldmParams.hashLog -
serialState->params.ldmParams.bucketSizeLog;
+ size_t const numBuckets = (size_t)1 << bucketLog;
/* Size the seq pool tables */
ZSTDMT_setNbSeq(seqPool, ZSTD_ldm_getMaxNbSeq(params.ldmParams, jobSize));
/* Reset the window */
@@ -501,20 +499,20 @@ ZSTDMT_serialState_reset(serialState_t* serialState,
}
if (serialState->ldmState.bucketOffsets == NULL || prevBucketLog < bucketLog) {
ZSTD_customFree(serialState->ldmState.bucketOffsets, cMem);
- serialState->ldmState.bucketOffsets = (BYTE*)ZSTD_customMalloc(bucketSize, cMem);
+ serialState->ldmState.bucketOffsets = (BYTE*)ZSTD_customMalloc(numBuckets, cMem);
}
if (!serialState->ldmState.hashTable || !serialState->ldmState.bucketOffsets)
return 1;
/* Zero the tables */
ZSTD_memset(serialState->ldmState.hashTable, 0, hashSize);
- ZSTD_memset(serialState->ldmState.bucketOffsets, 0, bucketSize);
+ ZSTD_memset(serialState->ldmState.bucketOffsets, 0, numBuckets);
/* Update window state and fill hash table with dict */
serialState->ldmState.loadedDictEnd = 0;
if (dictSize > 0) {
if (dictContentType == ZSTD_dct_rawContent) {
BYTE const* const dictEnd = (const BYTE*)dict + dictSize;
- ZSTD_window_update(&serialState->ldmState.window, dict, dictSize);
+ ZSTD_window_update(&serialState->ldmState.window, dict, dictSize, /* forceNonContiguous */ 0);
ZSTD_ldm_fillHashTable(&serialState->ldmState, (const BYTE*)dict, dictEnd, &params.ldmParams);
serialState->ldmState.loadedDictEnd = params.forceWindow ? 0 : (U32)(dictEnd - serialState->ldmState.window.base);
} else {
@@ -571,7 +569,7 @@ static void ZSTDMT_serialState_update(serialState_t* serialState,
assert(seqStore.seq != NULL && seqStore.pos == 0 &&
seqStore.size == 0 && seqStore.capacity > 0);
assert(src.size <= serialState->params.jobSize);
- ZSTD_window_update(&serialState->ldmState.window, src.start, src.size);
+ ZSTD_window_update(&serialState->ldmState.window, src.start, src.size, /* forceNonContiguous */ 0);
error = ZSTD_ldm_generateSequences(
&serialState->ldmState, &seqStore,
&serialState->params.ldmParams, src.start, src.size);
@@ -683,6 +681,8 @@ static void ZSTDMT_compressionJob(void* jobDescription)
if (job->jobID != 0) jobParams.fParams.checksumFlag = 0;
/* Don't run LDM for the chunks, since we handle it externally */
jobParams.ldmParams.enableLdm = 0;
+ /* Correct nbWorkers to 0. */
+ jobParams.nbWorkers = 0;
/* init */
@@ -695,6 +695,10 @@ static void ZSTDMT_compressionJob(void* jobDescription)
{ size_t const forceWindowError = ZSTD_CCtxParams_setParameter(&jobParams, ZSTD_c_forceMaxWindow, !job->firstJob);
if (ZSTD_isError(forceWindowError)) JOB_ERROR(forceWindowError);
}
+ if (!job->firstJob) {
+ size_t const err = ZSTD_CCtxParams_setParameter(&jobParams, ZSTD_c_deterministicRefPrefix, 0);
+ if (ZSTD_isError(err)) JOB_ERROR(err);
+ }
{ size_t const initError = ZSTD_compressBegin_advanced_internal(cctx,
job->prefix.start, job->prefix.size, ZSTD_dct_rawContent, /* load dictionary in "content-only" mode (no header analysis) */
ZSTD_dtlm_fast,
@@ -750,6 +754,13 @@ static void ZSTDMT_compressionJob(void* jobDescription)
if (ZSTD_isError(cSize)) JOB_ERROR(cSize);
lastCBlockSize = cSize;
} }
+ if (!job->firstJob) {
+ /* Double check that we don't have an ext-dict, because then our
+ * repcode invalidation doesn't work.
+ */
+ assert(!ZSTD_window_hasExtDict(cctx->blockState.matchState.window));
+ }
+ ZSTD_CCtx_trace(cctx, 0);
_endJob:
ZSTDMT_serialState_ensureFinished(job->serial, job->jobID, job->cSize);
@@ -1239,9 +1250,8 @@ size_t ZSTDMT_initCStream_internal(
if (params.rsyncable) {
/* Aim for the targetsectionSize as the average job size. */
- U32 const jobSizeMB = (U32)(mtctx->targetSectionSize >> 20);
- U32 const rsyncBits = ZSTD_highbit32(jobSizeMB) + 20;
- assert(jobSizeMB >= 1);
+ U32 const jobSizeKB = (U32)(mtctx->targetSectionSize >> 10);
+ U32 const rsyncBits = (assert(jobSizeKB >= 1), ZSTD_highbit32(jobSizeKB) + 10);
DEBUGLOG(4, "rsyncLog = %u", rsyncBits);
mtctx->rsync.hash = 0;
mtctx->rsync.hitMask = (1ULL << rsyncBits) - 1;
diff --git a/thirdparty/zstd/compress/zstdmt_compress.h b/thirdparty/zstd/compress/zstdmt_compress.h
index 0a9e551c99..2fee2ec745 100644
--- a/thirdparty/zstd/compress/zstdmt_compress.h
+++ b/thirdparty/zstd/compress/zstdmt_compress.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
@@ -32,11 +32,11 @@
/* === Constants === */
-#ifndef ZSTDMT_NBWORKERS_MAX
-# define ZSTDMT_NBWORKERS_MAX 200
+#ifndef ZSTDMT_NBWORKERS_MAX /* a different value can be selected at compile time */
+# define ZSTDMT_NBWORKERS_MAX ((sizeof(void*)==4) /*32-bit*/ ? 64 : 256)
#endif
-#ifndef ZSTDMT_JOBSIZE_MIN
-# define ZSTDMT_JOBSIZE_MIN (1 MB)
+#ifndef ZSTDMT_JOBSIZE_MIN /* a different value can be selected at compile time */
+# define ZSTDMT_JOBSIZE_MIN (512 KB)
#endif
#define ZSTDMT_JOBLOG_MAX (MEM_32bits() ? 29 : 30)
#define ZSTDMT_JOBSIZE_MAX (MEM_32bits() ? (512 MB) : (1024 MB))
diff --git a/thirdparty/zstd/decompress/huf_decompress.c b/thirdparty/zstd/decompress/huf_decompress.c
index 1418206718..b93c9a003b 100644
--- a/thirdparty/zstd/decompress/huf_decompress.c
+++ b/thirdparty/zstd/decompress/huf_decompress.c
@@ -1,7 +1,7 @@
/* ******************************************************************
* huff0 huffman decoder,
* part of Finite State Entropy library
- * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
*
* You can contact the author at :
* - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
@@ -528,13 +528,15 @@ typedef rankValCol_t rankVal_t[HUF_TABLELOG_MAX];
static void HUF_fillDTableX2Level2(HUF_DEltX2* DTable, U32 sizeLog, const U32 consumed,
const U32* rankValOrigin, const int minWeight,
const sortedSymbol_t* sortedSymbols, const U32 sortedListSize,
- U32 nbBitsBaseline, U16 baseSeq)
+ U32 nbBitsBaseline, U16 baseSeq, U32* wksp, size_t wkspSize)
{
HUF_DEltX2 DElt;
- U32 rankVal[HUF_TABLELOG_MAX + 1];
+ U32* rankVal = wksp;
+ assert(wkspSize >= HUF_TABLELOG_MAX + 1);
+ (void)wkspSize;
/* get pre-calculated rankVal */
- ZSTD_memcpy(rankVal, rankValOrigin, sizeof(rankVal));
+ ZSTD_memcpy(rankVal, rankValOrigin, sizeof(U32) * (HUF_TABLELOG_MAX + 1));
/* fill skipped values */
if (minWeight>1) {
@@ -569,14 +571,18 @@ static void HUF_fillDTableX2Level2(HUF_DEltX2* DTable, U32 sizeLog, const U32 co
static void HUF_fillDTableX2(HUF_DEltX2* DTable, const U32 targetLog,
const sortedSymbol_t* sortedList, const U32 sortedListSize,
const U32* rankStart, rankVal_t rankValOrigin, const U32 maxWeight,
- const U32 nbBitsBaseline)
+ const U32 nbBitsBaseline, U32* wksp, size_t wkspSize)
{
- U32 rankVal[HUF_TABLELOG_MAX + 1];
+ U32* rankVal = wksp;
const int scaleLog = nbBitsBaseline - targetLog; /* note : targetLog >= srcLog, hence scaleLog <= 1 */
const U32 minBits = nbBitsBaseline - maxWeight;
U32 s;
- ZSTD_memcpy(rankVal, rankValOrigin, sizeof(rankVal));
+ assert(wkspSize >= HUF_TABLELOG_MAX + 1);
+ wksp += HUF_TABLELOG_MAX + 1;
+ wkspSize -= HUF_TABLELOG_MAX + 1;
+
+ ZSTD_memcpy(rankVal, rankValOrigin, sizeof(U32) * (HUF_TABLELOG_MAX + 1));
/* fill DTable */
for (s=0; s<sortedListSize; s++) {
@@ -594,7 +600,7 @@ static void HUF_fillDTableX2(HUF_DEltX2* DTable, const U32 targetLog,
HUF_fillDTableX2Level2(DTable+start, targetLog-nbBits, nbBits,
rankValOrigin[nbBits], minWeight,
sortedList+sortedRank, sortedListSize-sortedRank,
- nbBitsBaseline, symbol);
+ nbBitsBaseline, symbol, wksp, wkspSize);
} else {
HUF_DEltX2 DElt;
MEM_writeLE16(&(DElt.sequence), symbol);
@@ -608,6 +614,15 @@ static void HUF_fillDTableX2(HUF_DEltX2* DTable, const U32 targetLog,
}
}
+typedef struct {
+ rankValCol_t rankVal[HUF_TABLELOG_MAX];
+ U32 rankStats[HUF_TABLELOG_MAX + 1];
+ U32 rankStart0[HUF_TABLELOG_MAX + 2];
+ sortedSymbol_t sortedSymbol[HUF_SYMBOLVALUE_MAX + 1];
+ BYTE weightList[HUF_SYMBOLVALUE_MAX + 1];
+ U32 calleeWksp[HUF_READ_STATS_WORKSPACE_SIZE_U32];
+} HUF_ReadDTableX2_Workspace;
+
size_t HUF_readDTableX2_wksp(HUF_DTable* DTable,
const void* src, size_t srcSize,
void* workSpace, size_t wkspSize)
@@ -620,47 +635,32 @@ size_t HUF_readDTableX2_wksp(HUF_DTable* DTable,
HUF_DEltX2* const dt = (HUF_DEltX2*)dtPtr;
U32 *rankStart;
- rankValCol_t* rankVal;
- U32* rankStats;
- U32* rankStart0;
- sortedSymbol_t* sortedSymbol;
- BYTE* weightList;
- size_t spaceUsed32 = 0;
-
- rankVal = (rankValCol_t *)((U32 *)workSpace + spaceUsed32);
- spaceUsed32 += (sizeof(rankValCol_t) * HUF_TABLELOG_MAX) >> 2;
- rankStats = (U32 *)workSpace + spaceUsed32;
- spaceUsed32 += HUF_TABLELOG_MAX + 1;
- rankStart0 = (U32 *)workSpace + spaceUsed32;
- spaceUsed32 += HUF_TABLELOG_MAX + 2;
- sortedSymbol = (sortedSymbol_t *)workSpace + (spaceUsed32 * sizeof(U32)) / sizeof(sortedSymbol_t);
- spaceUsed32 += HUF_ALIGN(sizeof(sortedSymbol_t) * (HUF_SYMBOLVALUE_MAX + 1), sizeof(U32)) >> 2;
- weightList = (BYTE *)((U32 *)workSpace + spaceUsed32);
- spaceUsed32 += HUF_ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2;
-
- if ((spaceUsed32 << 2) > wkspSize) return ERROR(tableLog_tooLarge);
-
- rankStart = rankStart0 + 1;
- ZSTD_memset(rankStats, 0, sizeof(U32) * (2 * HUF_TABLELOG_MAX + 2 + 1));
+ HUF_ReadDTableX2_Workspace* const wksp = (HUF_ReadDTableX2_Workspace*)workSpace;
+
+ if (sizeof(*wksp) > wkspSize) return ERROR(GENERIC);
+
+ rankStart = wksp->rankStart0 + 1;
+ ZSTD_memset(wksp->rankStats, 0, sizeof(wksp->rankStats));
+ ZSTD_memset(wksp->rankStart0, 0, sizeof(wksp->rankStart0));
DEBUG_STATIC_ASSERT(sizeof(HUF_DEltX2) == sizeof(HUF_DTable)); /* if compiler fails here, assertion is wrong */
if (maxTableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge);
/* ZSTD_memset(weightList, 0, sizeof(weightList)); */ /* is not necessary, even though some analyzer complain ... */
- iSize = HUF_readStats(weightList, HUF_SYMBOLVALUE_MAX + 1, rankStats, &nbSymbols, &tableLog, src, srcSize);
+ iSize = HUF_readStats_wksp(wksp->weightList, HUF_SYMBOLVALUE_MAX + 1, wksp->rankStats, &nbSymbols, &tableLog, src, srcSize, wksp->calleeWksp, sizeof(wksp->calleeWksp), /* bmi2 */ 0);
if (HUF_isError(iSize)) return iSize;
/* check result */
if (tableLog > maxTableLog) return ERROR(tableLog_tooLarge); /* DTable can't fit code depth */
/* find maxWeight */
- for (maxW = tableLog; rankStats[maxW]==0; maxW--) {} /* necessarily finds a solution before 0 */
+ for (maxW = tableLog; wksp->rankStats[maxW]==0; maxW--) {} /* necessarily finds a solution before 0 */
/* Get start index of each weight */
{ U32 w, nextRankStart = 0;
for (w=1; w<maxW+1; w++) {
U32 curr = nextRankStart;
- nextRankStart += rankStats[w];
+ nextRankStart += wksp->rankStats[w];
rankStart[w] = curr;
}
rankStart[0] = nextRankStart; /* put all 0w symbols at the end of sorted list*/
@@ -670,37 +670,38 @@ size_t HUF_readDTableX2_wksp(HUF_DTable* DTable,
/* sort symbols by weight */
{ U32 s;
for (s=0; s<nbSymbols; s++) {
- U32 const w = weightList[s];
+ U32 const w = wksp->weightList[s];
U32 const r = rankStart[w]++;
- sortedSymbol[r].symbol = (BYTE)s;
- sortedSymbol[r].weight = (BYTE)w;
+ wksp->sortedSymbol[r].symbol = (BYTE)s;
+ wksp->sortedSymbol[r].weight = (BYTE)w;
}
rankStart[0] = 0; /* forget 0w symbols; this is beginning of weight(1) */
}
/* Build rankVal */
- { U32* const rankVal0 = rankVal[0];
+ { U32* const rankVal0 = wksp->rankVal[0];
{ int const rescale = (maxTableLog-tableLog) - 1; /* tableLog <= maxTableLog */
U32 nextRankVal = 0;
U32 w;
for (w=1; w<maxW+1; w++) {
U32 curr = nextRankVal;
- nextRankVal += rankStats[w] << (w+rescale);
+ nextRankVal += wksp->rankStats[w] << (w+rescale);
rankVal0[w] = curr;
} }
{ U32 const minBits = tableLog+1 - maxW;
U32 consumed;
for (consumed = minBits; consumed < maxTableLog - minBits + 1; consumed++) {
- U32* const rankValPtr = rankVal[consumed];
+ U32* const rankValPtr = wksp->rankVal[consumed];
U32 w;
for (w = 1; w < maxW+1; w++) {
rankValPtr[w] = rankVal0[w] >> consumed;
} } } }
HUF_fillDTableX2(dt, maxTableLog,
- sortedSymbol, sizeOfSort,
- rankStart0, rankVal, maxW,
- tableLog+1);
+ wksp->sortedSymbol, sizeOfSort,
+ wksp->rankStart0, wksp->rankVal, maxW,
+ tableLog+1,
+ wksp->calleeWksp, sizeof(wksp->calleeWksp) / sizeof(U32));
dtd.tableLog = (BYTE)maxTableLog;
dtd.tableType = 1;
@@ -1225,7 +1226,7 @@ size_t HUF_decompress1X1 (void* dst, size_t dstSize, const void* cSrc, size_t cS
HUF_CREATE_STATIC_DTABLEX1(DTable, HUF_TABLELOG_MAX);
return HUF_decompress1X1_DCtx (DTable, dst, dstSize, cSrc, cSrcSize);
}
-#endif
+#endif
#ifndef HUF_FORCE_DECOMPRESS_X1
size_t HUF_readDTableX2(HUF_DTable* DTable, const void* src, size_t srcSize)
diff --git a/thirdparty/zstd/decompress/zstd_ddict.c b/thirdparty/zstd/decompress/zstd_ddict.c
index f5cc23b387..ce335477b3 100644
--- a/thirdparty/zstd/decompress/zstd_ddict.c
+++ b/thirdparty/zstd/decompress/zstd_ddict.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
diff --git a/thirdparty/zstd/decompress/zstd_ddict.h b/thirdparty/zstd/decompress/zstd_ddict.h
index 8906a71c94..bd03268b50 100644
--- a/thirdparty/zstd/decompress/zstd_ddict.h
+++ b/thirdparty/zstd/decompress/zstd_ddict.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
diff --git a/thirdparty/zstd/decompress/zstd_decompress.c b/thirdparty/zstd/decompress/zstd_decompress.c
index 21f846bc77..910bc034c0 100644
--- a/thirdparty/zstd/decompress/zstd_decompress.c
+++ b/thirdparty/zstd/decompress/zstd_decompress.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
@@ -62,6 +62,7 @@
#include "../common/fse.h"
#define HUF_STATIC_LINKING_ONLY
#include "../common/huf.h"
+#include "../common/xxhash.h" /* XXH64_reset, XXH64_update, XXH64_digest, XXH64 */
#include "../common/zstd_internal.h" /* blockProperties_t */
#include "zstd_decompress_internal.h" /* ZSTD_DCtx */
#include "zstd_ddict.h" /* ZSTD_DDictDictContent */
@@ -72,6 +73,144 @@
#endif
+
+/*************************************
+ * Multiple DDicts Hashset internals *
+ *************************************/
+
+#define DDICT_HASHSET_MAX_LOAD_FACTOR_COUNT_MULT 4
+#define DDICT_HASHSET_MAX_LOAD_FACTOR_SIZE_MULT 3 /* These two constants represent SIZE_MULT/COUNT_MULT load factor without using a float.
+ * Currently, that means a 0.75 load factor.
+ * So, if count * COUNT_MULT / size * SIZE_MULT != 0, then we've exceeded
+ * the load factor of the ddict hash set.
+ */
+
+#define DDICT_HASHSET_TABLE_BASE_SIZE 64
+#define DDICT_HASHSET_RESIZE_FACTOR 2
+
+/* Hash function to determine starting position of dict insertion within the table
+ * Returns an index between [0, hashSet->ddictPtrTableSize]
+ */
+static size_t ZSTD_DDictHashSet_getIndex(const ZSTD_DDictHashSet* hashSet, U32 dictID) {
+ const U64 hash = XXH64(&dictID, sizeof(U32), 0);
+ /* DDict ptr table size is a multiple of 2, use size - 1 as mask to get index within [0, hashSet->ddictPtrTableSize) */
+ return hash & (hashSet->ddictPtrTableSize - 1);
+}
+
+/* Adds DDict to a hashset without resizing it.
+ * If inserting a DDict with a dictID that already exists in the set, replaces the one in the set.
+ * Returns 0 if successful, or a zstd error code if something went wrong.
+ */
+static size_t ZSTD_DDictHashSet_emplaceDDict(ZSTD_DDictHashSet* hashSet, const ZSTD_DDict* ddict) {
+ const U32 dictID = ZSTD_getDictID_fromDDict(ddict);
+ size_t idx = ZSTD_DDictHashSet_getIndex(hashSet, dictID);
+ const size_t idxRangeMask = hashSet->ddictPtrTableSize - 1;
+ RETURN_ERROR_IF(hashSet->ddictPtrCount == hashSet->ddictPtrTableSize, GENERIC, "Hash set is full!");
+ DEBUGLOG(4, "Hashed index: for dictID: %u is %zu", dictID, idx);
+ while (hashSet->ddictPtrTable[idx] != NULL) {
+ /* Replace existing ddict if inserting ddict with same dictID */
+ if (ZSTD_getDictID_fromDDict(hashSet->ddictPtrTable[idx]) == dictID) {
+ DEBUGLOG(4, "DictID already exists, replacing rather than adding");
+ hashSet->ddictPtrTable[idx] = ddict;
+ return 0;
+ }
+ idx &= idxRangeMask;
+ idx++;
+ }
+ DEBUGLOG(4, "Final idx after probing for dictID %u is: %zu", dictID, idx);
+ hashSet->ddictPtrTable[idx] = ddict;
+ hashSet->ddictPtrCount++;
+ return 0;
+}
+
+/* Expands hash table by factor of DDICT_HASHSET_RESIZE_FACTOR and
+ * rehashes all values, allocates new table, frees old table.
+ * Returns 0 on success, otherwise a zstd error code.
+ */
+static size_t ZSTD_DDictHashSet_expand(ZSTD_DDictHashSet* hashSet, ZSTD_customMem customMem) {
+ size_t newTableSize = hashSet->ddictPtrTableSize * DDICT_HASHSET_RESIZE_FACTOR;
+ const ZSTD_DDict** newTable = (const ZSTD_DDict**)ZSTD_customCalloc(sizeof(ZSTD_DDict*) * newTableSize, customMem);
+ const ZSTD_DDict** oldTable = hashSet->ddictPtrTable;
+ size_t oldTableSize = hashSet->ddictPtrTableSize;
+ size_t i;
+
+ DEBUGLOG(4, "Expanding DDict hash table! Old size: %zu new size: %zu", oldTableSize, newTableSize);
+ RETURN_ERROR_IF(!newTable, memory_allocation, "Expanded hashset allocation failed!");
+ hashSet->ddictPtrTable = newTable;
+ hashSet->ddictPtrTableSize = newTableSize;
+ hashSet->ddictPtrCount = 0;
+ for (i = 0; i < oldTableSize; ++i) {
+ if (oldTable[i] != NULL) {
+ FORWARD_IF_ERROR(ZSTD_DDictHashSet_emplaceDDict(hashSet, oldTable[i]), "");
+ }
+ }
+ ZSTD_customFree((void*)oldTable, customMem);
+ DEBUGLOG(4, "Finished re-hash");
+ return 0;
+}
+
+/* Fetches a DDict with the given dictID
+ * Returns the ZSTD_DDict* with the requested dictID. If it doesn't exist, then returns NULL.
+ */
+static const ZSTD_DDict* ZSTD_DDictHashSet_getDDict(ZSTD_DDictHashSet* hashSet, U32 dictID) {
+ size_t idx = ZSTD_DDictHashSet_getIndex(hashSet, dictID);
+ const size_t idxRangeMask = hashSet->ddictPtrTableSize - 1;
+ DEBUGLOG(4, "Hashed index: for dictID: %u is %zu", dictID, idx);
+ for (;;) {
+ size_t currDictID = ZSTD_getDictID_fromDDict(hashSet->ddictPtrTable[idx]);
+ if (currDictID == dictID || currDictID == 0) {
+ /* currDictID == 0 implies a NULL ddict entry */
+ break;
+ } else {
+ idx &= idxRangeMask; /* Goes to start of table when we reach the end */
+ idx++;
+ }
+ }
+ DEBUGLOG(4, "Final idx after probing for dictID %u is: %zu", dictID, idx);
+ return hashSet->ddictPtrTable[idx];
+}
+
+/* Allocates space for and returns a ddict hash set
+ * The hash set's ZSTD_DDict* table has all values automatically set to NULL to begin with.
+ * Returns NULL if allocation failed.
+ */
+static ZSTD_DDictHashSet* ZSTD_createDDictHashSet(ZSTD_customMem customMem) {
+ ZSTD_DDictHashSet* ret = (ZSTD_DDictHashSet*)ZSTD_customMalloc(sizeof(ZSTD_DDictHashSet), customMem);
+ DEBUGLOG(4, "Allocating new hash set");
+ ret->ddictPtrTable = (const ZSTD_DDict**)ZSTD_customCalloc(DDICT_HASHSET_TABLE_BASE_SIZE * sizeof(ZSTD_DDict*), customMem);
+ ret->ddictPtrTableSize = DDICT_HASHSET_TABLE_BASE_SIZE;
+ ret->ddictPtrCount = 0;
+ if (!ret || !ret->ddictPtrTable) {
+ return NULL;
+ }
+ return ret;
+}
+
+/* Frees the table of ZSTD_DDict* within a hashset, then frees the hashset itself.
+ * Note: The ZSTD_DDict* within the table are NOT freed.
+ */
+static void ZSTD_freeDDictHashSet(ZSTD_DDictHashSet* hashSet, ZSTD_customMem customMem) {
+ DEBUGLOG(4, "Freeing ddict hash set");
+ if (hashSet && hashSet->ddictPtrTable) {
+ ZSTD_customFree((void*)hashSet->ddictPtrTable, customMem);
+ }
+ if (hashSet) {
+ ZSTD_customFree(hashSet, customMem);
+ }
+}
+
+/* Public function: Adds a DDict into the ZSTD_DDictHashSet, possibly triggering a resize of the hash set.
+ * Returns 0 on success, or a ZSTD error.
+ */
+static size_t ZSTD_DDictHashSet_addDDict(ZSTD_DDictHashSet* hashSet, const ZSTD_DDict* ddict, ZSTD_customMem customMem) {
+ DEBUGLOG(4, "Adding dict ID: %u to hashset with - Count: %zu Tablesize: %zu", ZSTD_getDictID_fromDDict(ddict), hashSet->ddictPtrCount, hashSet->ddictPtrTableSize);
+ if (hashSet->ddictPtrCount * DDICT_HASHSET_MAX_LOAD_FACTOR_COUNT_MULT / hashSet->ddictPtrTableSize * DDICT_HASHSET_MAX_LOAD_FACTOR_SIZE_MULT != 0) {
+ FORWARD_IF_ERROR(ZSTD_DDictHashSet_expand(hashSet, customMem), "");
+ }
+ FORWARD_IF_ERROR(ZSTD_DDictHashSet_emplaceDDict(hashSet, ddict), "");
+ return 0;
+}
+
/*-*************************************************************
* Context management
***************************************************************/
@@ -101,6 +240,7 @@ static void ZSTD_DCtx_resetParameters(ZSTD_DCtx* dctx)
dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT;
dctx->outBufferMode = ZSTD_bm_buffered;
dctx->forceIgnoreChecksum = ZSTD_d_validateChecksum;
+ dctx->refMultipleDDicts = ZSTD_rmd_refSingleDDict;
}
static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx)
@@ -120,8 +260,8 @@ static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx)
dctx->noForwardProgress = 0;
dctx->oversizedDuration = 0;
dctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
+ dctx->ddictSet = NULL;
ZSTD_DCtx_resetParameters(dctx);
- dctx->validateChecksum = 1;
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
dctx->dictContentEndForFuzzing = NULL;
#endif
@@ -178,6 +318,10 @@ size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx)
if (dctx->legacyContext)
ZSTD_freeLegacyStreamContext(dctx->legacyContext, dctx->previousLegacyVersion);
#endif
+ if (dctx->ddictSet) {
+ ZSTD_freeDDictHashSet(dctx->ddictSet, cMem);
+ dctx->ddictSet = NULL;
+ }
ZSTD_customFree(dctx, cMem);
return 0;
}
@@ -190,6 +334,29 @@ void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx)
ZSTD_memcpy(dstDCtx, srcDCtx, toCopy); /* no need to copy workspace */
}
+/* Given a dctx with a digested frame params, re-selects the correct ZSTD_DDict based on
+ * the requested dict ID from the frame. If there exists a reference to the correct ZSTD_DDict, then
+ * accordingly sets the ddict to be used to decompress the frame.
+ *
+ * If no DDict is found, then no action is taken, and the ZSTD_DCtx::ddict remains as-is.
+ *
+ * ZSTD_d_refMultipleDDicts must be enabled for this function to be called.
+ */
+static void ZSTD_DCtx_selectFrameDDict(ZSTD_DCtx* dctx) {
+ assert(dctx->refMultipleDDicts && dctx->ddictSet);
+ DEBUGLOG(4, "Adjusting DDict based on requested dict ID from frame");
+ if (dctx->ddict) {
+ const ZSTD_DDict* frameDDict = ZSTD_DDictHashSet_getDDict(dctx->ddictSet, dctx->fParams.dictID);
+ if (frameDDict) {
+ DEBUGLOG(4, "DDict found!");
+ ZSTD_clearDict(dctx);
+ dctx->dictID = dctx->fParams.dictID;
+ dctx->ddict = frameDDict;
+ dctx->dictUses = ZSTD_use_indefinitely;
+ }
+ }
+}
+
/*-*************************************************************
* Frame header decoding
@@ -441,12 +608,19 @@ unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize)
/** ZSTD_decodeFrameHeader() :
* `headerSize` must be the size provided by ZSTD_frameHeaderSize().
+ * If multiple DDict references are enabled, also will choose the correct DDict to use.
* @return : 0 if success, or an error code, which can be tested using ZSTD_isError() */
static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t headerSize)
{
size_t const result = ZSTD_getFrameHeader_advanced(&(dctx->fParams), src, headerSize, dctx->format);
if (ZSTD_isError(result)) return result; /* invalid header */
RETURN_ERROR_IF(result>0, srcSize_wrong, "headerSize too small");
+
+ /* Reference DDict requested by frame if dctx references multiple ddicts */
+ if (dctx->refMultipleDDicts == ZSTD_rmd_refMultipleDDicts && dctx->ddictSet) {
+ ZSTD_DCtx_selectFrameDDict(dctx);
+ }
+
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
/* Skip the dictID check in fuzzing mode, because it makes the search
* harder.
@@ -456,6 +630,7 @@ static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t he
#endif
dctx->validateChecksum = (dctx->fParams.checksumFlag && !dctx->forceIgnoreChecksum) ? 1 : 0;
if (dctx->validateChecksum) XXH64_reset(&dctx->xxhState, 0);
+ dctx->processedCSize += headerSize;
return 0;
}
@@ -578,7 +753,7 @@ unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize)
size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize)
{
DEBUGLOG(5, "ZSTD_insertBlock: %u bytes", (unsigned)blockSize);
- ZSTD_checkContinuity(dctx, blockStart);
+ ZSTD_checkContinuity(dctx, blockStart, blockSize);
dctx->previousDstEnd = (const char*)blockStart + blockSize;
return blockSize;
}
@@ -610,6 +785,32 @@ static size_t ZSTD_setRleBlock(void* dst, size_t dstCapacity,
return regenSize;
}
+static void ZSTD_DCtx_trace_end(ZSTD_DCtx const* dctx, U64 uncompressedSize, U64 compressedSize, unsigned streaming)
+{
+#if ZSTD_TRACE
+ if (dctx->traceCtx && ZSTD_trace_decompress_end != NULL) {
+ ZSTD_Trace trace;
+ ZSTD_memset(&trace, 0, sizeof(trace));
+ trace.version = ZSTD_VERSION_NUMBER;
+ trace.streaming = streaming;
+ if (dctx->ddict) {
+ trace.dictionaryID = ZSTD_getDictID_fromDDict(dctx->ddict);
+ trace.dictionarySize = ZSTD_DDict_dictSize(dctx->ddict);
+ trace.dictionaryIsCold = dctx->ddictIsCold;
+ }
+ trace.uncompressedSize = (size_t)uncompressedSize;
+ trace.compressedSize = (size_t)compressedSize;
+ trace.dctx = dctx;
+ ZSTD_trace_decompress_end(dctx->traceCtx, &trace);
+ }
+#else
+ (void)dctx;
+ (void)uncompressedSize;
+ (void)compressedSize;
+ (void)streaming;
+#endif
+}
+
/*! ZSTD_decompressFrame() :
* @dctx must be properly initialized
@@ -619,8 +820,9 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
void* dst, size_t dstCapacity,
const void** srcPtr, size_t *srcSizePtr)
{
- const BYTE* ip = (const BYTE*)(*srcPtr);
- BYTE* const ostart = (BYTE* const)dst;
+ const BYTE* const istart = (const BYTE*)(*srcPtr);
+ const BYTE* ip = istart;
+ BYTE* const ostart = (BYTE*)dst;
BYTE* const oend = dstCapacity != 0 ? ostart + dstCapacity : ostart;
BYTE* op = ostart;
size_t remainingSrcSize = *srcSizePtr;
@@ -695,7 +897,7 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
ip += 4;
remainingSrcSize -= 4;
}
-
+ ZSTD_DCtx_trace_end(dctx, (U64)(op-ostart), (U64)(ip-istart), /* streaming */ 0);
/* Allow caller to get size read */
*srcPtr = ip;
*srcSizePtr = remainingSrcSize;
@@ -764,7 +966,7 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
* use this in all cases but ddict */
FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDict(dctx, dict, dictSize), "");
}
- ZSTD_checkContinuity(dctx, dst);
+ ZSTD_checkContinuity(dctx, dst, dstCapacity);
{ const size_t res = ZSTD_decompressFrame(dctx, dst, dstCapacity,
&src, &srcSize);
@@ -899,7 +1101,9 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
DEBUGLOG(5, "ZSTD_decompressContinue (srcSize:%u)", (unsigned)srcSize);
/* Sanity check */
RETURN_ERROR_IF(srcSize != ZSTD_nextSrcSizeToDecompressWithInputSize(dctx, srcSize), srcSize_wrong, "not allowed");
- if (dstCapacity) ZSTD_checkContinuity(dctx, dst);
+ ZSTD_checkContinuity(dctx, dst, dstCapacity);
+
+ dctx->processedCSize += srcSize;
switch (dctx->stage)
{
@@ -1004,6 +1208,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
dctx->expected = 4;
dctx->stage = ZSTDds_checkChecksum;
} else {
+ ZSTD_DCtx_trace_end(dctx, dctx->decodedSize, dctx->processedCSize, /* streaming */ 1);
dctx->expected = 0; /* ends here */
dctx->stage = ZSTDds_getFrameHeaderSize;
}
@@ -1023,6 +1228,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
DEBUGLOG(4, "ZSTD_decompressContinue: checksum : calculated %08X :: %08X read", (unsigned)h32, (unsigned)check32);
RETURN_ERROR_IF(check32 != h32, checksum_wrong, "");
}
+ ZSTD_DCtx_trace_end(dctx, dctx->decodedSize, dctx->processedCSize, /* streaming */ 1);
dctx->expected = 0;
dctx->stage = ZSTDds_getFrameHeaderSize;
return 0;
@@ -1176,8 +1382,12 @@ static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict
size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx)
{
assert(dctx != NULL);
+#if ZSTD_TRACE
+ dctx->traceCtx = (ZSTD_trace_decompress_begin != NULL) ? ZSTD_trace_decompress_begin(dctx) : 0;
+#endif
dctx->expected = ZSTD_startingInputLength(dctx->format); /* dctx->format must be properly set */
dctx->stage = ZSTDds_getFrameHeaderSize;
+ dctx->processedCSize = 0;
dctx->decodedSize = 0;
dctx->previousDstEnd = NULL;
dctx->prefixStart = NULL;
@@ -1391,6 +1601,16 @@ size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict)
if (ddict) {
dctx->ddict = ddict;
dctx->dictUses = ZSTD_use_indefinitely;
+ if (dctx->refMultipleDDicts == ZSTD_rmd_refMultipleDDicts) {
+ if (dctx->ddictSet == NULL) {
+ dctx->ddictSet = ZSTD_createDDictHashSet(dctx->customMem);
+ if (!dctx->ddictSet) {
+ RETURN_ERROR(memory_allocation, "Failed to allocate memory for hash set!");
+ }
+ }
+ assert(!dctx->staticSize); /* Impossible: ddictSet cannot have been allocated if static dctx */
+ FORWARD_IF_ERROR(ZSTD_DDictHashSet_addDDict(dctx->ddictSet, ddict, dctx->customMem), "");
+ }
}
return 0;
}
@@ -1436,6 +1656,10 @@ ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam)
bounds.lowerBound = (int)ZSTD_d_validateChecksum;
bounds.upperBound = (int)ZSTD_d_ignoreChecksum;
return bounds;
+ case ZSTD_d_refMultipleDDicts:
+ bounds.lowerBound = (int)ZSTD_rmd_refSingleDDict;
+ bounds.upperBound = (int)ZSTD_rmd_refMultipleDDicts;
+ return bounds;
default:;
}
bounds.error = ERROR(parameter_unsupported);
@@ -1473,6 +1697,9 @@ size_t ZSTD_DCtx_getParameter(ZSTD_DCtx* dctx, ZSTD_dParameter param, int* value
case ZSTD_d_forceIgnoreChecksum:
*value = (int)dctx->forceIgnoreChecksum;
return 0;
+ case ZSTD_d_refMultipleDDicts:
+ *value = (int)dctx->refMultipleDDicts;
+ return 0;
default:;
}
RETURN_ERROR(parameter_unsupported, "");
@@ -1499,6 +1726,13 @@ size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter dParam, int value
CHECK_DBOUNDS(ZSTD_d_forceIgnoreChecksum, value);
dctx->forceIgnoreChecksum = (ZSTD_forceIgnoreChecksum_e)value;
return 0;
+ case ZSTD_d_refMultipleDDicts:
+ CHECK_DBOUNDS(ZSTD_d_refMultipleDDicts, value);
+ if (dctx->staticSize != 0) {
+ RETURN_ERROR(parameter_unsupported, "Static dctx does not support multiple DDicts!");
+ }
+ dctx->refMultipleDDicts = (ZSTD_refMultipleDDicts_e)value;
+ return 0;
default:;
}
RETURN_ERROR(parameter_unsupported, "");
@@ -1680,6 +1914,9 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
} }
#endif
{ size_t const hSize = ZSTD_getFrameHeader_advanced(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format);
+ if (zds->refMultipleDDicts && zds->ddictSet) {
+ ZSTD_DCtx_selectFrameDDict(zds);
+ }
DEBUGLOG(5, "header size : %u", (U32)hSize);
if (ZSTD_isError(hSize)) {
#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
diff --git a/thirdparty/zstd/decompress/zstd_decompress_block.c b/thirdparty/zstd/decompress/zstd_decompress_block.c
index 19cbdc5c16..349dcdc333 100644
--- a/thirdparty/zstd/decompress/zstd_decompress_block.c
+++ b/thirdparty/zstd/decompress/zstd_decompress_block.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
@@ -577,7 +577,7 @@ static size_t ZSTD_buildSeqTable(ZSTD_seqSymbol* DTableSpace, const ZSTD_seqSymb
size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr,
const void* src, size_t srcSize)
{
- const BYTE* const istart = (const BYTE* const)src;
+ const BYTE* const istart = (const BYTE*)src;
const BYTE* const iend = istart + srcSize;
const BYTE* ip = istart;
int nbSeq;
@@ -658,7 +658,6 @@ typedef struct {
size_t litLength;
size_t matchLength;
size_t offset;
- const BYTE* match;
} seq_t;
typedef struct {
@@ -672,9 +671,6 @@ typedef struct {
ZSTD_fseState stateOffb;
ZSTD_fseState stateML;
size_t prevOffset[ZSTD_REP_NUM];
- const BYTE* prefixStart;
- const BYTE* dictEnd;
- size_t pos;
} seqState_t;
/*! ZSTD_overlapCopy8() :
@@ -936,10 +932,9 @@ ZSTD_updateFseStateWithDInfo(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD, ZSTD
: 0)
typedef enum { ZSTD_lo_isRegularOffset, ZSTD_lo_isLongOffset=1 } ZSTD_longOffset_e;
-typedef enum { ZSTD_p_noPrefetch=0, ZSTD_p_prefetch=1 } ZSTD_prefetch_e;
FORCE_INLINE_TEMPLATE seq_t
-ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets, const ZSTD_prefetch_e prefetch)
+ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets)
{
seq_t seq;
ZSTD_seqSymbol const llDInfo = seqState->stateLL.table[seqState->stateLL.state];
@@ -1014,14 +1009,6 @@ ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets, c
DEBUGLOG(6, "seq: litL=%u, matchL=%u, offset=%u",
(U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset);
- if (prefetch == ZSTD_p_prefetch) {
- size_t const pos = seqState->pos + seq.litLength;
- const BYTE* const matchBase = (seq.offset > pos) ? seqState->dictEnd : seqState->prefixStart;
- seq.match = matchBase + pos - seq.offset; /* note : this operation can overflow when seq.offset is really too large, which can only happen when input is corrupted.
- * No consequence though : no memory access will occur, offset is only used for prefetching */
- seqState->pos = pos + seq.matchLength;
- }
-
/* ANS state update
* gcc-9.0.0 does 2.5% worse with ZSTD_updateFseStateWithDInfo().
* clang-9.2.0 does 7% worse with ZSTD_updateFseState().
@@ -1108,7 +1095,7 @@ ZSTD_decompressSequences_body( ZSTD_DCtx* dctx,
{
const BYTE* ip = (const BYTE*)seqStart;
const BYTE* const iend = ip + seqSize;
- BYTE* const ostart = (BYTE* const)dst;
+ BYTE* const ostart = (BYTE*)dst;
BYTE* const oend = ostart + maxDstSize;
BYTE* op = ostart;
const BYTE* litPtr = dctx->litPtr;
@@ -1122,7 +1109,6 @@ ZSTD_decompressSequences_body( ZSTD_DCtx* dctx,
/* Regen sequences */
if (nbSeq) {
seqState_t seqState;
- size_t error = 0;
dctx->fseEntropy = 1;
{ U32 i; for (i=0; i<ZSTD_REP_NUM; i++) seqState.prevOffset[i] = dctx->entropy.rep[i]; }
RETURN_ERROR_IF(
@@ -1156,13 +1142,14 @@ ZSTD_decompressSequences_body( ZSTD_DCtx* dctx,
* If you see most cycles served out of the DSB you've hit the good case.
* If it is pretty even then you may be in an okay case.
*
- * I've been able to reproduce this issue on the following CPUs:
+ * This issue has been reproduced on the following CPUs:
* - Kabylake: Macbook Pro (15-inch, 2019) 2.4 GHz Intel Core i9
* Use Instruments->Counters to get DSB/MITE cycles.
* I never got performance swings, but I was able to
* go from the good case of mostly DSB to half of the
* cycles served from MITE.
* - Coffeelake: Intel i9-9900k
+ * - Coffeelake: Intel i7-9700k
*
* I haven't been able to reproduce the instability or DSB misses on any
* of the following CPUS:
@@ -1175,33 +1162,35 @@ ZSTD_decompressSequences_body( ZSTD_DCtx* dctx,
*
* https://gist.github.com/terrelln/9889fc06a423fd5ca6e99351564473f4
*/
+ __asm__(".p2align 6");
+ __asm__("nop");
__asm__(".p2align 5");
__asm__("nop");
+# if __GNUC__ >= 9
+ /* better for gcc-9 and gcc-10, worse for clang and gcc-8 */
+ __asm__(".p2align 3");
+# else
__asm__(".p2align 4");
+# endif
#endif
for ( ; ; ) {
- seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset, ZSTD_p_noPrefetch);
+ seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset);
size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litEnd, prefixStart, vBase, dictEnd);
#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE)
assert(!ZSTD_isError(oneSeqSize));
if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase);
#endif
+ if (UNLIKELY(ZSTD_isError(oneSeqSize)))
+ return oneSeqSize;
DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize);
- BIT_reloadDStream(&(seqState.DStream));
op += oneSeqSize;
- /* gcc and clang both don't like early returns in this loop.
- * Instead break and check for an error at the end of the loop.
- */
- if (UNLIKELY(ZSTD_isError(oneSeqSize))) {
- error = oneSeqSize;
+ if (UNLIKELY(!--nbSeq))
break;
- }
- if (UNLIKELY(!--nbSeq)) break;
+ BIT_reloadDStream(&(seqState.DStream));
}
/* check if reached exact end */
DEBUGLOG(5, "ZSTD_decompressSequences_body: after decode loop, remaining nbSeq : %i", nbSeq);
- if (ZSTD_isError(error)) return error;
RETURN_ERROR_IF(nbSeq, corruption_detected, "");
RETURN_ERROR_IF(BIT_reloadDStream(&seqState.DStream) < BIT_DStream_completed, corruption_detected, "");
/* save reps for next block */
@@ -1232,6 +1221,24 @@ ZSTD_decompressSequences_default(ZSTD_DCtx* dctx,
#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */
#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT
+
+FORCE_INLINE_TEMPLATE size_t
+ZSTD_prefetchMatch(size_t prefetchPos, seq_t const sequence,
+ const BYTE* const prefixStart, const BYTE* const dictEnd)
+{
+ prefetchPos += sequence.litLength;
+ { const BYTE* const matchBase = (sequence.offset > prefetchPos) ? dictEnd : prefixStart;
+ const BYTE* const match = matchBase + prefetchPos - sequence.offset; /* note : this operation can overflow when seq.offset is really too large, which can only happen when input is corrupted.
+ * No consequence though : memory address is only used for prefetching, not for dereferencing */
+ PREFETCH_L1(match); PREFETCH_L1(match+CACHELINE_SIZE); /* note : it's safe to invoke PREFETCH() on any memory address, including invalid ones */
+ }
+ return prefetchPos + sequence.matchLength;
+}
+
+/* This decoding function employs prefetching
+ * to reduce latency impact of cache misses.
+ * It's generally employed when block contains a significant portion of long-distance matches
+ * or when coupled with a "cold" dictionary */
FORCE_INLINE_TEMPLATE size_t
ZSTD_decompressSequencesLong_body(
ZSTD_DCtx* dctx,
@@ -1242,7 +1249,7 @@ ZSTD_decompressSequencesLong_body(
{
const BYTE* ip = (const BYTE*)seqStart;
const BYTE* const iend = ip + seqSize;
- BYTE* const ostart = (BYTE* const)dst;
+ BYTE* const ostart = (BYTE*)dst;
BYTE* const oend = ostart + maxDstSize;
BYTE* op = ostart;
const BYTE* litPtr = dctx->litPtr;
@@ -1254,18 +1261,17 @@ ZSTD_decompressSequencesLong_body(
/* Regen sequences */
if (nbSeq) {
-#define STORED_SEQS 4
+#define STORED_SEQS 8
#define STORED_SEQS_MASK (STORED_SEQS-1)
-#define ADVANCED_SEQS 4
+#define ADVANCED_SEQS STORED_SEQS
seq_t sequences[STORED_SEQS];
int const seqAdvance = MIN(nbSeq, ADVANCED_SEQS);
seqState_t seqState;
int seqNb;
+ size_t prefetchPos = (size_t)(op-prefixStart); /* track position relative to prefixStart */
+
dctx->fseEntropy = 1;
{ int i; for (i=0; i<ZSTD_REP_NUM; i++) seqState.prevOffset[i] = dctx->entropy.rep[i]; }
- seqState.prefixStart = prefixStart;
- seqState.pos = (size_t)(op-prefixStart);
- seqState.dictEnd = dictEnd;
assert(dst != NULL);
assert(iend >= ip);
RETURN_ERROR_IF(
@@ -1277,21 +1283,23 @@ ZSTD_decompressSequencesLong_body(
/* prepare in advance */
for (seqNb=0; (BIT_reloadDStream(&seqState.DStream) <= BIT_DStream_completed) && (seqNb<seqAdvance); seqNb++) {
- sequences[seqNb] = ZSTD_decodeSequence(&seqState, isLongOffset, ZSTD_p_prefetch);
- PREFETCH_L1(sequences[seqNb].match); PREFETCH_L1(sequences[seqNb].match + sequences[seqNb].matchLength - 1); /* note : it's safe to invoke PREFETCH() on any memory address, including invalid ones */
+ seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset);
+ prefetchPos = ZSTD_prefetchMatch(prefetchPos, sequence, prefixStart, dictEnd);
+ sequences[seqNb] = sequence;
}
RETURN_ERROR_IF(seqNb<seqAdvance, corruption_detected, "");
/* decode and decompress */
for ( ; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && (seqNb<nbSeq) ; seqNb++) {
- seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset, ZSTD_p_prefetch);
+ seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset);
size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequences[(seqNb-ADVANCED_SEQS) & STORED_SEQS_MASK], &litPtr, litEnd, prefixStart, dictStart, dictEnd);
#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE)
assert(!ZSTD_isError(oneSeqSize));
if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequences[(seqNb-ADVANCED_SEQS) & STORED_SEQS_MASK], prefixStart, dictStart);
#endif
if (ZSTD_isError(oneSeqSize)) return oneSeqSize;
- PREFETCH_L1(sequence.match); PREFETCH_L1(sequence.match + sequence.matchLength - 1); /* note : it's safe to invoke PREFETCH() on any memory address, including invalid ones */
+
+ prefetchPos = ZSTD_prefetchMatch(prefetchPos, sequence, prefixStart, dictEnd);
sequences[seqNb & STORED_SEQS_MASK] = sequence;
op += oneSeqSize;
}
@@ -1517,9 +1525,9 @@ ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
}
-void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst)
+void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst, size_t dstSize)
{
- if (dst != dctx->previousDstEnd) { /* not contiguous */
+ if (dst != dctx->previousDstEnd && dstSize > 0) { /* not contiguous */
dctx->dictEnd = dctx->previousDstEnd;
dctx->virtualStart = (const char*)dst - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart));
dctx->prefixStart = dst;
@@ -1533,7 +1541,7 @@ size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx,
const void* src, size_t srcSize)
{
size_t dSize;
- ZSTD_checkContinuity(dctx, dst);
+ ZSTD_checkContinuity(dctx, dst, dstCapacity);
dSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 0);
dctx->previousDstEnd = (char*)dst + dSize;
return dSize;
diff --git a/thirdparty/zstd/decompress/zstd_decompress_block.h b/thirdparty/zstd/decompress/zstd_decompress_block.h
index b5715c168e..049a0cd84c 100644
--- a/thirdparty/zstd/decompress/zstd_decompress_block.h
+++ b/thirdparty/zstd/decompress/zstd_decompress_block.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
diff --git a/thirdparty/zstd/decompress/zstd_decompress_internal.h b/thirdparty/zstd/decompress/zstd_decompress_internal.h
index f80b471e99..ebda0c9031 100644
--- a/thirdparty/zstd/decompress/zstd_decompress_internal.h
+++ b/thirdparty/zstd/decompress/zstd_decompress_internal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
@@ -99,6 +99,13 @@ typedef enum {
ZSTD_use_once = 1 /* Use the dictionary once and set to ZSTD_dont_use */
} ZSTD_dictUses_e;
+/* Hashset for storing references to multiple ZSTD_DDict within ZSTD_DCtx */
+typedef struct {
+ const ZSTD_DDict** ddictPtrTable;
+ size_t ddictPtrTableSize;
+ size_t ddictPtrCount;
+} ZSTD_DDictHashSet;
+
struct ZSTD_DCtx_s
{
const ZSTD_seqSymbol* LLTptr;
@@ -113,6 +120,7 @@ struct ZSTD_DCtx_s
const void* dictEnd; /* end of previous segment */
size_t expected;
ZSTD_frameHeader fParams;
+ U64 processedCSize;
U64 decodedSize;
blockType_e bType; /* used in ZSTD_decompressContinue(), store blockType between block header decoding and block decompression stages */
ZSTD_dStage stage;
@@ -136,6 +144,8 @@ struct ZSTD_DCtx_s
U32 dictID;
int ddictIsCold; /* if == 1 : dictionary is "new" for working context, and presumed "cold" (not in cpu cache) */
ZSTD_dictUses_e dictUses;
+ ZSTD_DDictHashSet* ddictSet; /* Hash set for multiple ddicts */
+ ZSTD_refMultipleDDicts_e refMultipleDDicts; /* User specified: if == 1, will allow references to multiple DDicts. Default == 0 (disabled) */
/* streaming */
ZSTD_dStreamStage streamStage;
@@ -166,6 +176,11 @@ struct ZSTD_DCtx_s
void const* dictContentBeginForFuzzing;
void const* dictContentEndForFuzzing;
#endif
+
+ /* Tracing */
+#if ZSTD_TRACE
+ ZSTD_TraceCtx traceCtx;
+#endif
}; /* typedef'd to ZSTD_DCtx within "zstd.h" */
@@ -184,7 +199,7 @@ size_t ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy,
* If yes, do nothing (continue on current segment).
* If not, classify previous segment as "external dictionary", and start a new segment.
* This function cannot fail. */
-void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst);
+void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst, size_t dstSize);
#endif /* ZSTD_DECOMPRESS_INTERNAL_H */
diff --git a/thirdparty/zstd/zstd.h b/thirdparty/zstd/zstd.h
index b0ecdf5538..4651e6c4dc 100644
--- a/thirdparty/zstd/zstd.h
+++ b/thirdparty/zstd/zstd.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
@@ -71,8 +71,8 @@ extern "C" {
/*------ Version ------*/
#define ZSTD_VERSION_MAJOR 1
-#define ZSTD_VERSION_MINOR 4
-#define ZSTD_VERSION_RELEASE 8
+#define ZSTD_VERSION_MINOR 5
+#define ZSTD_VERSION_RELEASE 0
#define ZSTD_VERSION_NUMBER (ZSTD_VERSION_MAJOR *100*100 + ZSTD_VERSION_MINOR *100 + ZSTD_VERSION_RELEASE)
/*! ZSTD_versionNumber() :
@@ -109,7 +109,6 @@ ZSTDLIB_API const char* ZSTD_versionString(void);
#define ZSTD_BLOCKSIZE_MAX (1<<ZSTD_BLOCKSIZELOG_MAX)
-
/***************************************
* Simple API
***************************************/
@@ -166,7 +165,7 @@ ZSTDLIB_API unsigned long long ZSTD_getFrameContentSize(const void *src, size_t
* @return : decompressed size of `src` frame content _if known and not empty_, 0 otherwise. */
ZSTDLIB_API unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize);
-/*! ZSTD_findFrameCompressedSize() :
+/*! ZSTD_findFrameCompressedSize() : Requires v1.4.0+
* `src` should point to the start of a ZSTD frame or skippable frame.
* `srcSize` must be >= first frame size
* @return : the compressed size of the first frame starting at `src`,
@@ -180,8 +179,9 @@ ZSTDLIB_API size_t ZSTD_findFrameCompressedSize(const void* src, size_t srcSize)
ZSTDLIB_API size_t ZSTD_compressBound(size_t srcSize); /*!< maximum compressed size in worst case single-pass scenario */
ZSTDLIB_API unsigned ZSTD_isError(size_t code); /*!< tells if a `size_t` function result is an error code */
ZSTDLIB_API const char* ZSTD_getErrorName(size_t code); /*!< provides readable string from an error code */
-ZSTDLIB_API int ZSTD_minCLevel(void); /*!< minimum negative compression level allowed */
+ZSTDLIB_API int ZSTD_minCLevel(void); /*!< minimum negative compression level allowed, requires v1.4.0+ */
ZSTDLIB_API int ZSTD_maxCLevel(void); /*!< maximum compression level available */
+ZSTDLIB_API int ZSTD_defaultCLevel(void); /*!< default compression level, specified by ZSTD_CLEVEL_DEFAULT, requires v1.5.0+ */
/***************************************
@@ -199,7 +199,7 @@ ZSTDLIB_API int ZSTD_maxCLevel(void); /*!< maximum compres
*/
typedef struct ZSTD_CCtx_s ZSTD_CCtx;
ZSTDLIB_API ZSTD_CCtx* ZSTD_createCCtx(void);
-ZSTDLIB_API size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx);
+ZSTDLIB_API size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx); /* accept NULL pointer */
/*! ZSTD_compressCCtx() :
* Same as ZSTD_compress(), using an explicit ZSTD_CCtx.
@@ -222,7 +222,7 @@ ZSTDLIB_API size_t ZSTD_compressCCtx(ZSTD_CCtx* cctx,
* Use one context per thread for parallel execution. */
typedef struct ZSTD_DCtx_s ZSTD_DCtx;
ZSTDLIB_API ZSTD_DCtx* ZSTD_createDCtx(void);
-ZSTDLIB_API size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx);
+ZSTDLIB_API size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx); /* accept NULL pointer */
/*! ZSTD_decompressDCtx() :
* Same as ZSTD_decompress(),
@@ -234,9 +234,9 @@ ZSTDLIB_API size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx,
const void* src, size_t srcSize);
-/***************************************
-* Advanced compression API
-***************************************/
+/*********************************************
+* Advanced compression API (Requires v1.4.0+)
+**********************************************/
/* API design :
* Parameters are pushed one by one into an existing context,
@@ -266,7 +266,6 @@ typedef enum { ZSTD_fast=1,
Only the order (from fast to strong) is guaranteed */
} ZSTD_strategy;
-
typedef enum {
/* compression parameters
@@ -332,7 +331,6 @@ typedef enum {
* The higher the value of selected strategy, the more complex it is,
* resulting in stronger and slower compression.
* Special: value 0 means "use default strategy". */
-
/* LDM mode parameters */
ZSTD_c_enableLongDistanceMatching=160, /* Enable long distance matching.
* This parameter is designed to improve compression ratio
@@ -389,7 +387,7 @@ typedef enum {
ZSTD_c_jobSize=401, /* Size of a compression job. This value is enforced only when nbWorkers >= 1.
* Each compression job is completed in parallel, so this value can indirectly impact the nb of active threads.
* 0 means default, which is dynamically determined based on compression parameters.
- * Job size must be a minimum of overlap size, or 1 MB, whichever is largest.
+ * Job size must be a minimum of overlap size, or ZSTDMT_JOBSIZE_MIN (= 512 KB), whichever is largest.
* The minimum size is automatically and transparently enforced. */
ZSTD_c_overlapLog=402, /* Control the overlap size, as a fraction of window size.
* The overlap size is an amount of data reloaded from previous job at the beginning of a new job.
@@ -419,6 +417,8 @@ typedef enum {
* ZSTD_c_stableOutBuffer
* ZSTD_c_blockDelimiters
* ZSTD_c_validateSequences
+ * ZSTD_c_splitBlocks
+ * ZSTD_c_useRowMatchFinder
* Because they are not stable, it's necessary to define ZSTD_STATIC_LINKING_ONLY to access them.
* note : never ever use experimentalParam? names directly;
* also, the enums values themselves are unstable and can still change.
@@ -434,7 +434,10 @@ typedef enum {
ZSTD_c_experimentalParam9=1006,
ZSTD_c_experimentalParam10=1007,
ZSTD_c_experimentalParam11=1008,
- ZSTD_c_experimentalParam12=1009
+ ZSTD_c_experimentalParam12=1009,
+ ZSTD_c_experimentalParam13=1010,
+ ZSTD_c_experimentalParam14=1011,
+ ZSTD_c_experimentalParam15=1012
} ZSTD_cParameter;
typedef struct {
@@ -519,9 +522,9 @@ ZSTDLIB_API size_t ZSTD_compress2( ZSTD_CCtx* cctx,
const void* src, size_t srcSize);
-/***************************************
-* Advanced decompression API
-***************************************/
+/***********************************************
+* Advanced decompression API (Requires v1.4.0+)
+************************************************/
/* The advanced API pushes parameters one by one into an existing DCtx context.
* Parameters are sticky, and remain valid for all following frames
@@ -546,12 +549,14 @@ typedef enum {
* ZSTD_d_format
* ZSTD_d_stableOutBuffer
* ZSTD_d_forceIgnoreChecksum
+ * ZSTD_d_refMultipleDDicts
* Because they are not stable, it's necessary to define ZSTD_STATIC_LINKING_ONLY to access them.
* note : never ever use experimentalParam? names directly
*/
ZSTD_d_experimentalParam1=1000,
ZSTD_d_experimentalParam2=1001,
- ZSTD_d_experimentalParam3=1002
+ ZSTD_d_experimentalParam3=1002,
+ ZSTD_d_experimentalParam4=1003
} ZSTD_dParameter;
@@ -665,7 +670,7 @@ typedef ZSTD_CCtx ZSTD_CStream; /**< CCtx and CStream are now effectively same
/* Continue to distinguish them for compatibility with older versions <= v1.2.0 */
/*===== ZSTD_CStream management functions =====*/
ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream(void);
-ZSTDLIB_API size_t ZSTD_freeCStream(ZSTD_CStream* zcs);
+ZSTDLIB_API size_t ZSTD_freeCStream(ZSTD_CStream* zcs); /* accept NULL pointer */
/*===== Streaming compression functions =====*/
typedef enum {
@@ -681,7 +686,7 @@ typedef enum {
: note : multithreaded compression will block to flush as much output as possible. */
} ZSTD_EndDirective;
-/*! ZSTD_compressStream2() :
+/*! ZSTD_compressStream2() : Requires v1.4.0+
* Behaves about the same as ZSTD_compressStream, with additional control on end directive.
* - Compression parameters are pushed into CCtx before starting compression, using ZSTD_CCtx_set*()
* - Compression parameters cannot be changed once compression is started (save a list of exceptions in multi-threading mode)
@@ -727,11 +732,11 @@ ZSTDLIB_API size_t ZSTD_CStreamOutSize(void); /**< recommended size for output
/* *****************************************************************************
- * This following is a legacy streaming API.
+ * This following is a legacy streaming API, available since v1.0+ .
* It can be replaced by ZSTD_CCtx_reset() and ZSTD_compressStream2().
* It is redundant, but remains fully supported.
- * Advanced parameters and dictionary compression can only be used through the
- * new API.
+ * Streaming in combination with advanced parameters and dictionary compression
+ * can only be used through the new API.
******************************************************************************/
/*!
@@ -786,7 +791,7 @@ typedef ZSTD_DCtx ZSTD_DStream; /**< DCtx and DStream are now effectively same
/* For compatibility with versions <= v1.2.0, prefer differentiating them. */
/*===== ZSTD_DStream management functions =====*/
ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream(void);
-ZSTDLIB_API size_t ZSTD_freeDStream(ZSTD_DStream* zds);
+ZSTDLIB_API size_t ZSTD_freeDStream(ZSTD_DStream* zds); /* accept NULL pointer */
/*===== Streaming decompression functions =====*/
@@ -809,7 +814,7 @@ ZSTDLIB_API size_t ZSTD_DStreamOutSize(void); /*!< recommended size for output
/*! ZSTD_compress_usingDict() :
* Compression at an explicit compression level using a Dictionary.
* A dictionary can be any arbitrary data segment (also called a prefix),
- * or a buffer with specified information (see dictBuilder/zdict.h).
+ * or a buffer with specified information (see zdict.h).
* Note : This function loads the dictionary, resulting in significant startup delay.
* It's intended for a dictionary used only once.
* Note 2 : When `dict == NULL || dictSize < 8` no dictionary is used. */
@@ -852,7 +857,8 @@ ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict(const void* dictBuffer, size_t dictSize
int compressionLevel);
/*! ZSTD_freeCDict() :
- * Function frees memory allocated by ZSTD_createCDict(). */
+ * Function frees memory allocated by ZSTD_createCDict().
+ * If a NULL pointer is passed, no operation is performed. */
ZSTDLIB_API size_t ZSTD_freeCDict(ZSTD_CDict* CDict);
/*! ZSTD_compress_usingCDict() :
@@ -874,7 +880,8 @@ typedef struct ZSTD_DDict_s ZSTD_DDict;
ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict(const void* dictBuffer, size_t dictSize);
/*! ZSTD_freeDDict() :
- * Function frees memory allocated with ZSTD_createDDict() */
+ * Function frees memory allocated with ZSTD_createDDict()
+ * If a NULL pointer is passed, no operation is performed. */
ZSTDLIB_API size_t ZSTD_freeDDict(ZSTD_DDict* ddict);
/*! ZSTD_decompress_usingDDict() :
@@ -890,19 +897,25 @@ ZSTDLIB_API size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx,
* Dictionary helper functions
*******************************/
-/*! ZSTD_getDictID_fromDict() :
+/*! ZSTD_getDictID_fromDict() : Requires v1.4.0+
* Provides the dictID stored within dictionary.
* if @return == 0, the dictionary is not conformant with Zstandard specification.
* It can still be loaded, but as a content-only dictionary. */
ZSTDLIB_API unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize);
-/*! ZSTD_getDictID_fromDDict() :
+/*! ZSTD_getDictID_fromCDict() : Requires v1.5.0+
+ * Provides the dictID of the dictionary loaded into `cdict`.
+ * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty.
+ * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */
+ZSTDLIB_API unsigned ZSTD_getDictID_fromCDict(const ZSTD_CDict* cdict);
+
+/*! ZSTD_getDictID_fromDDict() : Requires v1.4.0+
* Provides the dictID of the dictionary loaded into `ddict`.
* If @return == 0, the dictionary is not conformant to Zstandard specification, or empty.
* Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */
ZSTDLIB_API unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict);
-/*! ZSTD_getDictID_fromFrame() :
+/*! ZSTD_getDictID_fromFrame() : Requires v1.4.0+
* Provides the dictID required to decompressed the frame stored within `src`.
* If @return == 0, the dictID could not be decoded.
* This could for one of the following reasons :
@@ -916,7 +929,7 @@ ZSTDLIB_API unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize);
/*******************************************************************************
- * Advanced dictionary and prefix API
+ * Advanced dictionary and prefix API (Requires v1.4.0+)
*
* This API allows dictionaries to be used with ZSTD_compress2(),
* ZSTD_compressStream2(), and ZSTD_decompress(). Dictionaries are sticky, and
@@ -925,7 +938,7 @@ ZSTDLIB_API unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize);
******************************************************************************/
-/*! ZSTD_CCtx_loadDictionary() :
+/*! ZSTD_CCtx_loadDictionary() : Requires v1.4.0+
* Create an internal CDict from `dict` buffer.
* Decompression will have to use same dictionary.
* @result : 0, or an error code (which can be tested with ZSTD_isError()).
@@ -944,11 +957,11 @@ ZSTDLIB_API unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize);
* to precisely select how dictionary content must be interpreted. */
ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize);
-/*! ZSTD_CCtx_refCDict() :
+/*! ZSTD_CCtx_refCDict() : Requires v1.4.0+
* Reference a prepared dictionary, to be used for all next compressed frames.
* Note that compression parameters are enforced from within CDict,
* and supersede any compression parameter previously set within CCtx.
- * The parameters ignored are labled as "superseded-by-cdict" in the ZSTD_cParameter enum docs.
+ * The parameters ignored are labelled as "superseded-by-cdict" in the ZSTD_cParameter enum docs.
* The ignored parameters will be used again if the CCtx is returned to no-dictionary mode.
* The dictionary will remain valid for future compressed frames using same CCtx.
* @result : 0, or an error code (which can be tested with ZSTD_isError()).
@@ -958,7 +971,7 @@ ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, s
* Note 2 : CDict is just referenced, its lifetime must outlive its usage within CCtx. */
ZSTDLIB_API size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict);
-/*! ZSTD_CCtx_refPrefix() :
+/*! ZSTD_CCtx_refPrefix() : Requires v1.4.0+
* Reference a prefix (single-usage dictionary) for next compressed frame.
* A prefix is **only used once**. Tables are discarded at end of frame (ZSTD_e_end).
* Decompression will need same prefix to properly regenerate data.
@@ -979,7 +992,7 @@ ZSTDLIB_API size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict);
ZSTDLIB_API size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx,
const void* prefix, size_t prefixSize);
-/*! ZSTD_DCtx_loadDictionary() :
+/*! ZSTD_DCtx_loadDictionary() : Requires v1.4.0+
* Create an internal DDict from dict buffer,
* to be used to decompress next frames.
* The dictionary remains valid for all future frames, until explicitly invalidated.
@@ -996,9 +1009,16 @@ ZSTDLIB_API size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx,
*/
ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);
-/*! ZSTD_DCtx_refDDict() :
+/*! ZSTD_DCtx_refDDict() : Requires v1.4.0+
* Reference a prepared dictionary, to be used to decompress next frames.
* The dictionary remains active for decompression of future frames using same DCtx.
+ *
+ * If called with ZSTD_d_refMultipleDDicts enabled, repeated calls of this function
+ * will store the DDict references in a table, and the DDict used for decompression
+ * will be determined at decompression time, as per the dict ID in the frame.
+ * The memory for the table is allocated on the first call to refDDict, and can be
+ * freed with ZSTD_freeDCtx().
+ *
* @result : 0, or an error code (which can be tested with ZSTD_isError()).
* Note 1 : Currently, only one dictionary can be managed.
* Referencing a new dictionary effectively "discards" any previous one.
@@ -1007,7 +1027,7 @@ ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, s
*/
ZSTDLIB_API size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict);
-/*! ZSTD_DCtx_refPrefix() :
+/*! ZSTD_DCtx_refPrefix() : Requires v1.4.0+
* Reference a prefix (single-usage dictionary) to decompress next frame.
* This is the reverse operation of ZSTD_CCtx_refPrefix(),
* and must use the same prefix as the one used during compression.
@@ -1028,7 +1048,7 @@ ZSTDLIB_API size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx,
/* === Memory management === */
-/*! ZSTD_sizeof_*() :
+/*! ZSTD_sizeof_*() : Requires v1.4.0+
* These functions give the _current_ memory usage of selected object.
* Note that object memory usage can evolve (increase or decrease) over time. */
ZSTDLIB_API size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx);
@@ -1053,6 +1073,28 @@ ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict);
#if defined(ZSTD_STATIC_LINKING_ONLY) && !defined(ZSTD_H_ZSTD_STATIC_LINKING_ONLY)
#define ZSTD_H_ZSTD_STATIC_LINKING_ONLY
+/* Deprecation warnings :
+ * Should these warnings be a problem, it is generally possible to disable them,
+ * typically with -Wno-deprecated-declarations for gcc or _CRT_SECURE_NO_WARNINGS in Visual.
+ * Otherwise, it's also possible to define ZSTD_DISABLE_DEPRECATE_WARNINGS.
+ */
+#ifdef ZSTD_DISABLE_DEPRECATE_WARNINGS
+# define ZSTD_DEPRECATED(message) ZSTDLIB_API /* disable deprecation warnings */
+#else
+# if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */
+# define ZSTD_DEPRECATED(message) [[deprecated(message)]] ZSTDLIB_API
+# elif (defined(GNUC) && (GNUC > 4 || (GNUC == 4 && GNUC_MINOR >= 5))) || defined(__clang__)
+# define ZSTD_DEPRECATED(message) ZSTDLIB_API __attribute__((deprecated(message)))
+# elif defined(__GNUC__) && (__GNUC__ >= 3)
+# define ZSTD_DEPRECATED(message) ZSTDLIB_API __attribute__((deprecated))
+# elif defined(_MSC_VER)
+# define ZSTD_DEPRECATED(message) ZSTDLIB_API __declspec(deprecated(message))
+# else
+# pragma message("WARNING: You need to implement ZSTD_DEPRECATED for this compiler")
+# define ZSTD_DEPRECATED(message) ZSTDLIB_API
+# endif
+#endif /* ZSTD_DISABLE_DEPRECATE_WARNINGS */
+
/****************************************************************************************
* experimental API (static linking only)
****************************************************************************************
@@ -1206,6 +1248,12 @@ typedef enum {
} ZSTD_forceIgnoreChecksum_e;
typedef enum {
+ /* Note: this enum controls ZSTD_d_refMultipleDDicts */
+ ZSTD_rmd_refSingleDDict = 0,
+ ZSTD_rmd_refMultipleDDicts = 1
+} ZSTD_refMultipleDDicts_e;
+
+typedef enum {
/* Note: this enum and the behavior it controls are effectively internal
* implementation details of the compressor. They are expected to continue
* to evolve and should be considered only in the context of extremely
@@ -1253,6 +1301,11 @@ typedef enum {
ZSTD_lcm_uncompressed = 2 /**< Always emit uncompressed literals. */
} ZSTD_literalCompressionMode_e;
+typedef enum {
+ ZSTD_urm_auto = 0, /* Automatically determine whether or not we use row matchfinder */
+ ZSTD_urm_disableRowMatchFinder = 1, /* Never use row matchfinder */
+ ZSTD_urm_enableRowMatchFinder = 2 /* Always use row matchfinder when applicable */
+} ZSTD_useRowMatchFinderMode_e;
/***************************************
* Frame size functions
@@ -1286,7 +1339,7 @@ ZSTDLIB_API unsigned long long ZSTD_findDecompressedSize(const void* src, size_t
* `srcSize` must be the _exact_ size of this series
* (i.e. there should be a frame boundary at `src + srcSize`)
* @return : - upper-bound for the decompressed size of all data in all successive frames
- * - if an error occured: ZSTD_CONTENTSIZE_ERROR
+ * - if an error occurred: ZSTD_CONTENTSIZE_ERROR
*
* note 1 : an error can occur if `src` contains an invalid or incorrectly formatted frame.
* note 2 : the upper-bound is exact when the decompressed size field is available in every ZSTD encoded frame of `src`.
@@ -1372,6 +1425,23 @@ ZSTDLIB_API size_t ZSTD_compressSequences(ZSTD_CCtx* const cctx, void* dst, size
const void* src, size_t srcSize);
+/*! ZSTD_writeSkippableFrame() :
+ * Generates a zstd skippable frame containing data given by src, and writes it to dst buffer.
+ *
+ * Skippable frames begin with a a 4-byte magic number. There are 16 possible choices of magic number,
+ * ranging from ZSTD_MAGIC_SKIPPABLE_START to ZSTD_MAGIC_SKIPPABLE_START+15.
+ * As such, the parameter magicVariant controls the exact skippable frame magic number variant used, so
+ * the magic number used will be ZSTD_MAGIC_SKIPPABLE_START + magicVariant.
+ *
+ * Returns an error if destination buffer is not large enough, if the source size is not representable
+ * with a 4-byte unsigned int, or if the parameter magicVariant is greater than 15 (and therefore invalid).
+ *
+ * @return : number of bytes written or a ZSTD error.
+ */
+ZSTDLIB_API size_t ZSTD_writeSkippableFrame(void* dst, size_t dstCapacity,
+ const void* src, size_t srcSize, unsigned magicVariant);
+
+
/***************************************
* Memory management
***************************************/
@@ -1506,13 +1576,14 @@ ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictS
* Note that the lifetime of such pool must exist while being used.
* ZSTD_CCtx_refThreadPool assigns a thread pool to a context (use NULL argument value
* to use an internal thread pool).
- * ZSTD_freeThreadPool frees a thread pool.
+ * ZSTD_freeThreadPool frees a thread pool, accepts NULL pointer.
*/
typedef struct POOL_ctx_s ZSTD_threadPool;
ZSTDLIB_API ZSTD_threadPool* ZSTD_createThreadPool(size_t numThreads);
-ZSTDLIB_API void ZSTD_freeThreadPool (ZSTD_threadPool* pool);
+ZSTDLIB_API void ZSTD_freeThreadPool (ZSTD_threadPool* pool); /* accept NULL pointer */
ZSTDLIB_API size_t ZSTD_CCtx_refThreadPool(ZSTD_CCtx* cctx, ZSTD_threadPool* pool);
+
/*
* This API is temporary and is expected to change or disappear in the future!
*/
@@ -1523,10 +1594,12 @@ ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_advanced2(
const ZSTD_CCtx_params* cctxParams,
ZSTD_customMem customMem);
-ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize,
- ZSTD_dictLoadMethod_e dictLoadMethod,
- ZSTD_dictContentType_e dictContentType,
- ZSTD_customMem customMem);
+ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_advanced(
+ const void* dict, size_t dictSize,
+ ZSTD_dictLoadMethod_e dictLoadMethod,
+ ZSTD_dictContentType_e dictContentType,
+ ZSTD_customMem customMem);
+
/***************************************
* Advanced compression functions
@@ -1540,12 +1613,6 @@ ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictS
* note: equivalent to ZSTD_createCDict_advanced(), with dictLoadMethod==ZSTD_dlm_byRef */
ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_byReference(const void* dictBuffer, size_t dictSize, int compressionLevel);
-/*! ZSTD_getDictID_fromCDict() :
- * Provides the dictID of the dictionary loaded into `cdict`.
- * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty.
- * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */
-ZSTDLIB_API unsigned ZSTD_getDictID_fromCDict(const ZSTD_CDict* cdict);
-
/*! ZSTD_getCParams() :
* @return ZSTD_compressionParameters structure for a selected compression level and estimated srcSize.
* `estimatedSrcSize` value is optional, select 0 if not known */
@@ -1572,18 +1639,20 @@ ZSTDLIB_API ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParame
/*! ZSTD_compress_advanced() :
* Note : this function is now DEPRECATED.
* It can be replaced by ZSTD_compress2(), in combination with ZSTD_CCtx_setParameter() and other parameter setters.
- * This prototype will be marked as deprecated and generate compilation warning on reaching v1.5.x */
-ZSTDLIB_API size_t ZSTD_compress_advanced(ZSTD_CCtx* cctx,
+ * This prototype will generate compilation warnings. */
+ZSTD_DEPRECATED("use ZSTD_compress2")
+size_t ZSTD_compress_advanced(ZSTD_CCtx* cctx,
void* dst, size_t dstCapacity,
const void* src, size_t srcSize,
const void* dict,size_t dictSize,
ZSTD_parameters params);
/*! ZSTD_compress_usingCDict_advanced() :
- * Note : this function is now REDUNDANT.
+ * Note : this function is now DEPRECATED.
* It can be replaced by ZSTD_compress2(), in combination with ZSTD_CCtx_loadDictionary() and other parameter setters.
- * This prototype will be marked as deprecated and generate compilation warning in some future version */
-ZSTDLIB_API size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx,
+ * This prototype will generate compilation warnings. */
+ZSTD_DEPRECATED("use ZSTD_compress2 with ZSTD_CCtx_loadDictionary")
+size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx,
void* dst, size_t dstCapacity,
const void* src, size_t srcSize,
const ZSTD_CDict* cdict,
@@ -1645,7 +1714,7 @@ ZSTDLIB_API size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* pre
/* Controls how the literals are compressed (default is auto).
* The value must be of type ZSTD_literalCompressionMode_e.
- * See ZSTD_literalCompressionMode_t enum definition for details.
+ * See ZSTD_literalCompressionMode_e enum definition for details.
*/
#define ZSTD_c_literalCompressionMode ZSTD_c_experimentalParam5
@@ -1797,12 +1866,52 @@ ZSTDLIB_API size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* pre
*/
#define ZSTD_c_validateSequences ZSTD_c_experimentalParam12
+/* ZSTD_c_splitBlocks
+ * Default is 0 == disabled. Set to 1 to enable block splitting.
+ *
+ * Will attempt to split blocks in order to improve compression ratio at the cost of speed.
+ */
+#define ZSTD_c_splitBlocks ZSTD_c_experimentalParam13
+
+/* ZSTD_c_useRowMatchFinder
+ * Default is ZSTD_urm_auto.
+ * Controlled with ZSTD_useRowMatchFinderMode_e enum.
+ *
+ * By default, in ZSTD_urm_auto, when finalizing the compression parameters, the library
+ * will decide at runtime whether to use the row-based matchfinder based on support for SIMD
+ * instructions as well as the windowLog.
+ *
+ * Set to ZSTD_urm_disableRowMatchFinder to never use row-based matchfinder.
+ * Set to ZSTD_urm_enableRowMatchFinder to force usage of row-based matchfinder.
+ */
+#define ZSTD_c_useRowMatchFinder ZSTD_c_experimentalParam14
+
+/* ZSTD_c_deterministicRefPrefix
+ * Default is 0 == disabled. Set to 1 to enable.
+ *
+ * Zstd produces different results for prefix compression when the prefix is
+ * directly adjacent to the data about to be compressed vs. when it isn't.
+ * This is because zstd detects that the two buffers are contiguous and it can
+ * use a more efficient match finding algorithm. However, this produces different
+ * results than when the two buffers are non-contiguous. This flag forces zstd
+ * to always load the prefix in non-contiguous mode, even if it happens to be
+ * adjacent to the data, to guarantee determinism.
+ *
+ * If you really care about determinism when using a dictionary or prefix,
+ * like when doing delta compression, you should select this option. It comes
+ * at a speed penalty of about ~2.5% if the dictionary and data happened to be
+ * contiguous, and is free if they weren't contiguous. We don't expect that
+ * intentionally making the dictionary and data contiguous will be worth the
+ * cost to memcpy() the data.
+ */
+#define ZSTD_c_deterministicRefPrefix ZSTD_c_experimentalParam15
+
/*! ZSTD_CCtx_getParameter() :
* Get the requested compression parameter value, selected by enum ZSTD_cParameter,
* and store it into int* value.
* @return : 0, or an error code (which can be tested with ZSTD_isError()).
*/
-ZSTDLIB_API size_t ZSTD_CCtx_getParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value);
+ZSTDLIB_API size_t ZSTD_CCtx_getParameter(const ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value);
/*! ZSTD_CCtx_params :
@@ -1817,13 +1926,13 @@ ZSTDLIB_API size_t ZSTD_CCtx_getParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param
* These parameters will be applied to
* all subsequent frames.
* - ZSTD_compressStream2() : Do compression using the CCtx.
- * - ZSTD_freeCCtxParams() : Free the memory.
+ * - ZSTD_freeCCtxParams() : Free the memory, accept NULL pointer.
*
* This can be used with ZSTD_estimateCCtxSize_advanced_usingCCtxParams()
* for static allocation of CCtx for single-threaded compression.
*/
ZSTDLIB_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void);
-ZSTDLIB_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params);
+ZSTDLIB_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params); /* accept NULL pointer */
/*! ZSTD_CCtxParams_reset() :
* Reset params to default values.
@@ -1842,7 +1951,7 @@ ZSTDLIB_API size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compre
*/
ZSTDLIB_API size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params);
-/*! ZSTD_CCtxParams_setParameter() :
+/*! ZSTD_CCtxParams_setParameter() : Requires v1.4.0+
* Similar to ZSTD_CCtx_setParameter.
* Set one compression parameter, selected by enum ZSTD_cParameter.
* Parameters must be applied to a ZSTD_CCtx using
@@ -1857,7 +1966,7 @@ ZSTDLIB_API size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* params, ZSTD_c
* Get the requested value of one compression parameter, selected by enum ZSTD_cParameter.
* @result : 0, or an error code (which can be tested with ZSTD_isError()).
*/
-ZSTDLIB_API size_t ZSTD_CCtxParams_getParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, int* value);
+ZSTDLIB_API size_t ZSTD_CCtxParams_getParameter(const ZSTD_CCtx_params* params, ZSTD_cParameter param, int* value);
/*! ZSTD_CCtx_setParametersUsingCCtxParams() :
* Apply a set of ZSTD_CCtx_params to the compression context.
@@ -1983,12 +2092,38 @@ ZSTDLIB_API size_t ZSTD_DCtx_getParameter(ZSTD_DCtx* dctx, ZSTD_dParameter param
*/
#define ZSTD_d_forceIgnoreChecksum ZSTD_d_experimentalParam3
+/* ZSTD_d_refMultipleDDicts
+ * Experimental parameter.
+ * Default is 0 == disabled. Set to 1 to enable
+ *
+ * If enabled and dctx is allocated on the heap, then additional memory will be allocated
+ * to store references to multiple ZSTD_DDict. That is, multiple calls of ZSTD_refDDict()
+ * using a given ZSTD_DCtx, rather than overwriting the previous DDict reference, will instead
+ * store all references. At decompression time, the appropriate dictID is selected
+ * from the set of DDicts based on the dictID in the frame.
+ *
+ * Usage is simply calling ZSTD_refDDict() on multiple dict buffers.
+ *
+ * Param has values of byte ZSTD_refMultipleDDicts_e
+ *
+ * WARNING: Enabling this parameter and calling ZSTD_DCtx_refDDict(), will trigger memory
+ * allocation for the hash table. ZSTD_freeDCtx() also frees this memory.
+ * Memory is allocated as per ZSTD_DCtx::customMem.
+ *
+ * Although this function allocates memory for the table, the user is still responsible for
+ * memory management of the underlying ZSTD_DDict* themselves.
+ */
+#define ZSTD_d_refMultipleDDicts ZSTD_d_experimentalParam4
+
+
/*! ZSTD_DCtx_setFormat() :
+ * This function is REDUNDANT. Prefer ZSTD_DCtx_setParameter().
* Instruct the decoder context about what kind of data to decode next.
* This instruction is mandatory to decode data without a fully-formed header,
* such ZSTD_f_zstd1_magicless for example.
* @return : 0, or an error code (which can be tested using ZSTD_isError()). */
-ZSTDLIB_API size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format);
+ZSTD_DEPRECATED("use ZSTD_DCtx_setParameter() instead")
+size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format);
/*! ZSTD_decompressStream_simpleArgs() :
* Same as ZSTD_decompressStream(),
@@ -2012,7 +2147,7 @@ ZSTDLIB_API size_t ZSTD_decompressStream_simpleArgs (
/*===== Advanced Streaming compression functions =====*/
/*! ZSTD_initCStream_srcSize() :
- * This function is deprecated, and equivalent to:
+ * This function is DEPRECATED, and equivalent to:
* ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
* ZSTD_CCtx_refCDict(zcs, NULL); // clear the dictionary (if any)
* ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel);
@@ -2021,15 +2156,15 @@ ZSTDLIB_API size_t ZSTD_decompressStream_simpleArgs (
* pledgedSrcSize must be correct. If it is not known at init time, use
* ZSTD_CONTENTSIZE_UNKNOWN. Note that, for compatibility with older programs,
* "0" also disables frame content size field. It may be enabled in the future.
- * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x
+ * This prototype will generate compilation warnings.
*/
-ZSTDLIB_API size_t
-ZSTD_initCStream_srcSize(ZSTD_CStream* zcs,
+ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions")
+size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs,
int compressionLevel,
unsigned long long pledgedSrcSize);
/*! ZSTD_initCStream_usingDict() :
- * This function is deprecated, and is equivalent to:
+ * This function is DEPRECATED, and is equivalent to:
* ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
* ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel);
* ZSTD_CCtx_loadDictionary(zcs, dict, dictSize);
@@ -2038,15 +2173,15 @@ ZSTD_initCStream_srcSize(ZSTD_CStream* zcs,
* dict == NULL or dictSize < 8, in which case no dict is used.
* Note: dict is loaded with ZSTD_dct_auto (treated as a full zstd dictionary if
* it begins with ZSTD_MAGIC_DICTIONARY, else as raw content) and ZSTD_dlm_byCopy.
- * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x
+ * This prototype will generate compilation warnings.
*/
-ZSTDLIB_API size_t
-ZSTD_initCStream_usingDict(ZSTD_CStream* zcs,
+ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions")
+size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs,
const void* dict, size_t dictSize,
int compressionLevel);
/*! ZSTD_initCStream_advanced() :
- * This function is deprecated, and is approximately equivalent to:
+ * This function is DEPRECATED, and is approximately equivalent to:
* ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
* // Pseudocode: Set each zstd parameter and leave the rest as-is.
* for ((param, value) : params) {
@@ -2058,23 +2193,24 @@ ZSTD_initCStream_usingDict(ZSTD_CStream* zcs,
* dict is loaded with ZSTD_dct_auto and ZSTD_dlm_byCopy.
* pledgedSrcSize must be correct.
* If srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN.
- * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x
+ * This prototype will generate compilation warnings.
*/
-ZSTDLIB_API size_t
-ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
+ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions")
+size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
const void* dict, size_t dictSize,
ZSTD_parameters params,
unsigned long long pledgedSrcSize);
/*! ZSTD_initCStream_usingCDict() :
- * This function is deprecated, and equivalent to:
+ * This function is DEPRECATED, and equivalent to:
* ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
* ZSTD_CCtx_refCDict(zcs, cdict);
- *
+ *
* note : cdict will just be referenced, and must outlive compression session
- * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x
+ * This prototype will generate compilation warnings.
*/
-ZSTDLIB_API size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict);
+ZSTD_DEPRECATED("use ZSTD_CCtx_reset and ZSTD_CCtx_refCDict, see zstd.h for detailed instructions")
+size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict);
/*! ZSTD_initCStream_usingCDict_advanced() :
* This function is DEPRECATED, and is approximately equivalent to:
@@ -2089,18 +2225,21 @@ ZSTDLIB_API size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDi
* same as ZSTD_initCStream_usingCDict(), with control over frame parameters.
* pledgedSrcSize must be correct. If srcSize is not known at init time, use
* value ZSTD_CONTENTSIZE_UNKNOWN.
- * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x
+ * This prototype will generate compilation warnings.
*/
-ZSTDLIB_API size_t
-ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs,
+ZSTD_DEPRECATED("use ZSTD_CCtx_reset and ZSTD_CCtx_refCDict, see zstd.h for detailed instructions")
+size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs,
const ZSTD_CDict* cdict,
ZSTD_frameParameters fParams,
unsigned long long pledgedSrcSize);
/*! ZSTD_resetCStream() :
- * This function is deprecated, and is equivalent to:
+ * This function is DEPRECATED, and is equivalent to:
* ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
* ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize);
+ * Note: ZSTD_resetCStream() interprets pledgedSrcSize == 0 as ZSTD_CONTENTSIZE_UNKNOWN, but
+ * ZSTD_CCtx_setPledgedSrcSize() does not do the same, so ZSTD_CONTENTSIZE_UNKNOWN must be
+ * explicitly specified.
*
* start a new frame, using same parameters from previous frame.
* This is typically useful to skip dictionary loading stage, since it will re-use it in-place.
@@ -2110,9 +2249,10 @@ ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs,
* For the time being, pledgedSrcSize==0 is interpreted as "srcSize unknown" for compatibility with older programs,
* but it will change to mean "empty" in future version, so use macro ZSTD_CONTENTSIZE_UNKNOWN instead.
* @return : 0, or an error code (which can be tested using ZSTD_isError())
- * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x
+ * This prototype will generate compilation warnings.
*/
-ZSTDLIB_API size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize);
+ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions")
+size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize);
typedef struct {
@@ -2199,8 +2339,7 @@ ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds);
ZSTD_CCtx object can be re-used multiple times within successive compression operations.
Start by initializing a context.
- Use ZSTD_compressBegin(), or ZSTD_compressBegin_usingDict() for dictionary compression,
- or ZSTD_compressBegin_advanced(), for finer parameter control.
+ Use ZSTD_compressBegin(), or ZSTD_compressBegin_usingDict() for dictionary compression.
It's also possible to duplicate a reference context which has already been initialized, using ZSTD_copyCCtx()
Then, consume your input using ZSTD_compressContinue().
@@ -2225,15 +2364,17 @@ ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds);
/*===== Buffer-less streaming compression functions =====*/
ZSTDLIB_API size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel);
ZSTDLIB_API size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel);
-ZSTDLIB_API size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize); /**< pledgedSrcSize : If srcSize is not known at init time, use ZSTD_CONTENTSIZE_UNKNOWN */
ZSTDLIB_API size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); /**< note: fails if cdict==NULL */
-ZSTDLIB_API size_t ZSTD_compressBegin_usingCDict_advanced(ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize); /* compression parameters are already set within cdict. pledgedSrcSize must be correct. If srcSize is not known, use macro ZSTD_CONTENTSIZE_UNKNOWN */
ZSTDLIB_API size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, unsigned long long pledgedSrcSize); /**< note: if pledgedSrcSize is not known, use ZSTD_CONTENTSIZE_UNKNOWN */
ZSTDLIB_API size_t ZSTD_compressContinue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
ZSTDLIB_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
-
+/* The ZSTD_compressBegin_advanced() and ZSTD_compressBegin_usingCDict_advanced() are now DEPRECATED and will generate a compiler warning */
+ZSTD_DEPRECATED("use advanced API to access custom parameters")
+size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize); /**< pledgedSrcSize : If srcSize is not known at init time, use ZSTD_CONTENTSIZE_UNKNOWN */
+ZSTD_DEPRECATED("use advanced API to access custom parameters")
+size_t ZSTD_compressBegin_usingCDict_advanced(ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize); /* compression parameters are already set within cdict. pledgedSrcSize must be correct. If srcSize is not known, use macro ZSTD_CONTENTSIZE_UNKNOWN */
/**
Buffer-less streaming decompression (synchronous mode)
diff --git a/thirdparty/zstd/common/zstd_errors.h b/thirdparty/zstd/zstd_errors.h
index 6d0d003004..fa3686b772 100644
--- a/thirdparty/zstd/common/zstd_errors.h
+++ b/thirdparty/zstd/zstd_errors.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the